I have a code as following, here I want to throw errors if the client code does not match any of specializations. But static assert is not helping the cause. Please suggest how to achieve it.
struct storage_manager{
storage_impl<double> double_store;
storage_impl<std::string> string_store;
template<typename T>
bool try_getting(int key, T &value)
{
static_assert(false , "Compiler should not reach here");
return false;
}
storage_manager(){}
~storage_manager(){}
storage_manager(storage_manager const &) = delete;
};
Specialization for double type.
template<>
inline bool storage_manager::try_getting<double>(int key, double &value)
{
return double_store.try_getting(key,value);
}
specializations for std::string type.
template<>
inline bool storage_manager::try_getting<std::string>(int key, std::string &value)
{
return string_store.try_getting(key,value);
}
How to throw errors at compile time when an unsupported type is requested. like...
storage_manager mgr;
int a;
std::cout<<mgr.try_getting(134,a);
You can do
template<typename T>
bool try_getting(int key, T &value) = delete;
and implement only the desired specializations. Example:
#include <iostream>
template<typename> void f() = delete;
template <> void f<int>(){std::cout << "ok\n";}
int main()
{
f<int>();
// f<double>(); // does not compile
}
Live on Coliru
Related
I am trying to figure out how the sfinae concept works in C++. But I can't convince the object-type compiler if bool is true or false.
#include <iostream>
class A {
public:
void foo() { std::cout << "a\n"; }
};
class B {
public:
void ioo() { std::cout << "b\n"; }
};
template<class T>
void f(const T& ob, bool value = false)
{
if constexpr (!value) ob.foo();
else ob.ioo();
}
int main()
{
A ob1;
B ob2;
f(ob1, true);
f(ob2, false);
}
You need to let the bool parameter to be part of template. In your case, bool value is a run time parameter.
By adding the value as non-template parameter, your code can compile:
template<bool Flag, class T>
// ^^^^^^^^
void f(const T& ob)
{
if constexpr (Flag) {
ob.foo();
}
else
ob.ioo();
}
and you may call like:
f<true>(ob1);
f<false>(ob2);
As a side note, your A::foo() and B::ioo() must be const qualified member functions, as you want to call, with a const objects of each classes inside the f.
That being said, the bool parameter is redundant if you can use the std::is_same
#include <type_traits> // std::is_same
template<class T>
void f(const T& ob)
{
if constexpr (std::is_same_v<T, A>) {
ob.foo();
}
else if constexpr (std::is_same_v<T, B>)
ob.ioo();
}
Now call needs to be just:
f(ob1);
f(ob2);
I have something similar to this (stripped down example to the relevant points)
struct Foo
{
template <typename T>
constexpr std::enable_if<someTrait<T>::value ,T>::type& get() const { return something(); }
template <typename T>
std::enable_if<someOtherTrait<T>::value ,T>::type& get() { return somethingDifferent(); }
class Nested
{
public:
template <typename T>
T& get() { return foo.get<T>(); }
private:
Foo& foo;
}
}
e.g. Foo::get evaluates to a const constexpr function or something completely non-const depending on the template type.
Now I want to be able to do this
class Bar : public Foo::Nested
{
void nonConstFn()
{
auto& a = get<TypeA>();
//...
}
void constFn() const // <===== Won't compile
{
auto& a = get<TypeA>();
//...
}
}
It's obvious that Bar::constFn won't compile as it calls the non-const function Foo::Nested::get<TypeA> – even if TypeA would satisfy someTrait and call the const function constexpr Foo::get<TypeA>() const again in the end.
Leaving the constexpr aside for now, how do I propagate the constness of the called function in my nested class' function template? I tried simply overloading it with a const and non-const version of Nested::get which solves it for clang on macOS but fails with MSVC in Visual Studio 2015 on Windows, which is unfortunately a required build target.
Note that the original example contains a lot more than just two versions of Foo::get so I'd like to avoid repeating all versions in Foo::Nested but forward it with one or two function templates if possible
Edit: I tried the proposal to use
template <typename T>
constexpr auto get() const -> decltype(foo.get<T>()) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> decltype(foo.get<T>()) { return foo.get<T>(); }
on godbolt.org which seems to compile fine for current MSVC versions but fails with Visual Studio 2015 MSVC 19.0, so this is no option
First of you need enable_if::type for the SFINAE to work.
To get to your question you need to overload Nested::get:
#include <type_traits>
struct Foo
{
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const
{ return something(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get()
{ return somethingDifferent(); }
int& something() const;
float& somethingDifferent();
class Nested
{
public:
Nested();
template <typename T>
constexpr std::enable_if_t<std::is_integral_v<T>, T>&
get() const { return foo.get<T>(); }
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>&
get() { return foo.get<T>(); }
private:
Foo& foo;
};
};
class Bar : public Foo::Nested
{
void nonConstFn()
{
[[maybe_unused]] auto& a = get<int>();
[[maybe_unused]] auto& b = get<float>();
}
void constFn() const
{
[[maybe_unused]] auto& a = get<int>();
}
};
You need const and non-const overload in Nested, you might avoid to repeat all overload/SFINAE with another (simple) SFINAE:
class Nested
{
Foo& foo; // Should be declared before the decltype usage
public:
Nested();
template <typename T>
constexpr auto get() const -> (decltype(foo.get<T>())) { return foo.get<T>(); }
template <typename T>
constexpr auto get() -> (decltype(foo.get<T>())) { return foo.get<T>(); }
};
Consider the following problem, which is meaningless but proposes a solution to yours. You have a class with two functions and an invoker for them
class A
{
public: void foo() { printf("foo"); }
public: void foo() const { printf("foo const"); }
public: void invoke() { foo(); }
}
If you do A().invoke(), you will get foo obviously. If you want to force to execute the const type function, how do you achieve that? OK, you make the following change
A::invoke() { const_cast<const A*>(this)->foo(); } and that's it.
Background:
I'm working on a query DSL that'll parse expressions with ==, <, etc., and return filter objects via operator overloading.
Problem:
My template method is failing when used with a string literal. I've tried providing specific instantiations of the template taking both std::string, and char but neither seems to work.
The code is below. The line causing the problem in main is marked with a comment. Alternative solutions I've tried are commented out within the code.
A runnable repl of the same code can be found here.
I do know that manually wrapping the string literal with std::string("text") will work, but I want to be able to use plain string literals, if at all possible.
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
// template <signed N>
// Filter<std::string> operator==(const char (&val) [N]);
template <typename T>
Filter<T> operator==(const T &val);
};
template <typename T>
Filter<T> Field::operator==(const T &val)
{
return Filter<T>{ *this, val, "==" };
}
// template <signed N>
// Filter<std::string> Field::operator==(const char (&val) [N])
// {
// return Filter<std::string>{ *this, std::string(val), "==" };
// }
// template <>
// Filter<std::string> Field::operator==<std::string>(const std::string &val)
// {
// return Filter<std::string>{ *this, val, "==" };
// }
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
std::cout << (f1 == "Hello").val; // <--- the source of my problems
}
Issue is that c-array is not copyable, so
Filter<char [6]>{ *this, val, "==" }; // Error
Your overload is correct, but Filter needs to reordered and defined before your operator== overload. The overload returning Filter<T> is dependent on T, and so in that case Filter's definition can be postponed. But when you return Filter<std::string> the compiler needs an actual definition of Filter up front.
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
template <std::size_t N> Filter<std::string> operator==(const char (&val) [N]);
template <typename T>
Filter<T> operator==(const T &val);
};
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
template <typename T>
Filter<T> Field::operator==(const T &val)
{
return Filter<T>{ *this, val, "==" };
}
template <std::size_t N>
Filter<std::string> Field::operator==(const char (&val) [N])
{
return Filter<std::string>{ *this, std::string(val), "==" };
}
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
std::cout << (f1 == "Hello").val;
}
Demo
What you can do is specialize Filter for the case when T gets deduced to a char[N]. Adding
template<std::size_t N>
struct Filter<char[N]>
{
Field f;
std::string val;
std::string op;
};
Will cause Filter<T>{ *this, val, "==" } to call the above specialization and it will use a std::string to store val.
Since you have the C++17 tag, here is yet another option to solve this problem: deduction guides
#include <iostream>
template<typename T>
struct Filter;
struct Field
{
Field(const std::string &val): name(val) { }
Field(std::string &&val): name(std::move(val)) { }
std::string name;
// note the use of auto here
template <typename T>
auto operator==(const T &val);
};
template <typename T>
auto Field::operator==(const T &val)
{
// do not use Filter<T> here, or the deduction guide won't kick in
return Filter{ *this, val, "==" };
}
template<typename T>
struct Filter
{
Field f;
T val;
std::string op;
};
// ------- Deduction Guides -----------
template<typename T>
Filter(Field, T, std::string) -> Filter<T>;
// will tell the compiler to create a Filter<string> with a c-array argument
template<std::size_t N>
Filter(Field, const char(&)[N], std::string) -> Filter<std::string>;
// ------------------------------------
int main() {
Field f1 { "field1" };
Field f2 { "field1" };
std::cout << (f1 == 1).val;
// creates a Filter<string> instead of trying to
// create a Filter<const char(&)[6]> due to the deduction guide
std::cout << (f1 == "Hello").val;
}
C++ Primer 5th Edition has a snippet of advice at the end of chapter 16.3 (a chapter discussing function template overloading):
Declare every function in an overload set before you define any of the
functions. That way you don’t have to worry whether the compiler will
instantiate a call before it sees the function you intended to call.
So is this telling me that in choosing the candidate and viable functions during overload resolution it is possible the compiler might instantiate a function template that isn't chosen in the end? I tried to see whether this might actually happen:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <typename T> void test(T*) { }
int main(){
int *q = nullptr;
test(q); //test(T*) should be the best match
}
This program would throw a compiler error if test(T const &) was instantiated in any form, except the program compiles fine as expected. So what kind of compilation mishap is that tip trying to guard me from? When would it ever instantiate a function before it saw the function I was trying to call?
The author is warning you of this:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
int main(){
int *q = nullptr;
test(q); //test(T*) will not be matched.
}
template <typename T> void test(T*)
{
}
And these:
template<class> struct always_false : std::false_type {};
template <typename T> void test(T const &){
static_assert(always_false<T>::value, "If this fires, it is instantiated");
}
template <> void test<int>(int const &);
void test(int *);
int main(){
int *q = nullptr;
test(q); //test(int*) should be the best match
int a;
test(a); // test<int>(int const&) should be the best match
}
template <> void test<int>(int const &)
{
}
void test(int *)
{
}
If you don't provide declarations of
template <> void test<int>(int const &);
void test(int *);
before main, they won't be matched in main.
I've seen plenty of SO questions that is some variation of
template<class T, class... Ts>
T sum(T t, Ts... ts) { return t + sum(ts...); }
// ^ |
// |--------------------------------
// only one visible in
// definition context
template<class T>
T sum(T t) { return t; }
int main() {
sum(1, 2); // doesn't compile
}
(The return type isn't perfect, but you get the idea.)
And then people are surprised when it doesn't compile.
Or, even more fun,
template<class T> void f(T t) { f((int)t); }
void f(int) { /*...*/ }
int main() {
f(1L); // infinite recursion
}
I'm trying to port a C++ project to iOS. It compiles just fine in QtCreator on Linux and Windows and also on MSVC.
Now on Xcode/GCC, with a certain templated class I get the following error: "error: too few template-parameter-lists".
The code that causes this error looks something like this:
template <typename TA, typename TB, int Type>
class MyClassImpl
{
public:
MyClassImpl();
virtual int GetType() const
{
return type;
}
};
typedef MyClassImpl<float, int, 12> MyFloatIntClass;
MyFloatIntClass::MyFloatIntClass()
{
...
}
int MyFloatIntClass::GetType() const
{
return 22;
}
I'm guessing that something about the typedef syntax is illegal and GCC is more strict on the standard.
Can anybody tell me what exactly the problem is and how I can fix it?
As you're defining full specializations of methods of the respective class, you'll still need to prefix the definitions with template <>, which is the "template-parameter-lists" you're missing. Furthermore, the constructor must be named as the class is, so MyFloatIntClass::MyFloatIntClass() is illegal (as MyFloatIntClass is just an alias, not a class name). The following compiles fine for me (g++ 4.5.3):
template <typename TA, typename TB, int Type>
class MyClassImpl
{
public:
MyClassImpl();
virtual int GetType() const
{
return Type;
}
};
typedef MyClassImpl<float, int, 12> MyFloatIntClass;
template <>
MyFloatIntClass::MyClassImpl()
{
}
template <>
int MyFloatIntClass::GetType() const
{
return 22;
}
This is just a guess, but do you need to add template<>?
Since it's a template specialization, I believe it still needs to be a template.
ex.
template<>
MyFloatIntClass::MyClassImpl() {}
template<>
int MyFloatIntClass::GetType() const {
return 22;
}
EDIT: From modelnine's answer- turns out it needs the untypedef'd name for the ctor.
EDIT2: The following code works fine for me:
template <typename TA, typename TB, int Type>
class MyClassImpl
{
public:
MyClassImpl();
MyClassImpl(const MyClassImpl<TA, TB, Type>&);
virtual int GetType() const
{
return Type;
}
const MyClassImpl<TA, TB, Type>& operator=(const MyClassImpl<TA, TB, Type>&);
};
typedef MyClassImpl<float, int, 12> MyFloatIntClass;
template<>
MyFloatIntClass::MyClassImpl()
{
//
}
template<>
MyFloatIntClass::MyClassImpl( const MyFloatIntClass& rhs )
{
//
}
template<>
const MyFloatIntClass& MyFloatIntClass::operator=( const MyFloatIntClass& rhs )
{
return *this;
}
template<>
int MyFloatIntClass::GetType() const
{
return 22;
}