Let's say I have a C++ class Foo. It has a templatized method setValue() that needs to accept any of the following as its argument:
Any primitive type
An object of type Bar
An object of a subclass of Bar
I want to write something like this.
template <class T>
void setValue(T& value) {
if (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
But this doesn't compile. When I call the method with an int, the compiler complains that dynamic_cast can't be used on an int*. Even though that code branch doesn't get executed for primitives, the compiler still needs to compile it.
How can I make this work? Note this is a method in a class, so template specializations aren't allowed.
Since C++17 you can easily address this problem with if constexpr.
As you can expect, it can exclude an entire branch from the compilation (rather than the execution, as a normal if).
Note: the code is still subjected to syntax rules. Details are out of the scope of this answer.
template <class T>
void setValue(T& value) {
if constexpr (std::is_fundamental<T>::value)
setPrimitiveValue(value)
else {
Bar* bar = dynamic_cast<Bar*>(&value);
if (bar != NULL)
setBarValue(*bar);
}
}
The answer from Biagio Festa looks perfect as long as you can use C++17. I can't since I still need to support older compilers, but that answer led me to Constexpr if alternative which gives several alternatives. Here's the solution I ended up with which works even on C++11.
template <class T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type setValue(T& value) {
setPrimitiveValue(value);
}
void setValue(Bar& value) {
setBarValue(value);
}
Related
This version doesn't compile at all:
struct A {
void foo() {
static_assert(0,"Fail");
}
};
This version compiles without errors (at least in my version of compiler):
template <int x>
struct B {
void foo() {
static_assert(x,"Fail");
}
};
B<0> b;
The second version fails to compile only when I call b.foo();, so I want to know is it permitted by the standard to use the second version if I never call method foo? Will all compilers behave in the same way? Isn't it undefined behavior?
I want to include static_assert in the code to forbid usage of some methods of a template class when some template parameters meet some criteria. Is it correct usage of static_assert?
I want to use this approach (I want to forbid usage of .z() when vector has only two dimensions) in this situation:
template <typename T, int D>
struct MyVecctor {
MyVecctor() : data({})
{}
template <typename... Args>
MyVecctor(Args... args) : data({args...})
{
static_assert(D > 0);
static_assert(sizeof...(args) == D);
}
T& operator[] (std::size_t index) {
return data[index];
}
T& x() {
static_assert(D>=1);
return data[0];
}
T& y() {
static_assert(D>=2);
return data[1];
}
T& z() {
static_assert(D>=3);
return data[2];
}
std::array<T, D> data;
};
The behavior here is well-defined. The significant difference here is that in second case result of static_assert depends on template parameter so it won't be resolved until this method is instantiated. If it didn't depend on template parameter then it would fail just like in first case without instantiating anything:
template <int x>
struct B {
void foo() {
static_assert(0,"Fail");
}
};
And yes, forbidding usage of some methods of a template class when some template parameters met some criteria is a correct usage of static_assert. And I would even say this is a preferred method of prohibiting method because it may yield a more readable error message (even with a potential fix suggestion) compared to usual template instantiation failure gibberish.
The bodies of a template class's methods are not instantiated unless called.
However, if we consider the instantiation of bodies of a template class's methods to be template instantiations (this is unclear in the standard), then there must be a valid set of template arguments that makes the body possible to instantiate; otherwise the program is ill-formed, no diagnostic required.
In your specific case, static_assert(x, "Fail") clearly has a valid instantiation (any x!=0). So you are safe.
However
void foo() {
static_assert(x&&!x, "Fail");
}
isn't going to be safe; by my reading, that is an ill-formed program with no diagnostic required. On the other hand, my reading might be wrong; the standard is pretty oblique here.
The philosophical reason why the above is wrong is that it permits compilers to detect for impossible assumptions in static asserts; it lets the compiler check more things in the bodies of templates than the standard demands, which is I believe why the standard makes uninstantable templates ill-formed, and no diagnostic requried is because they don't want to have to force every compiler to do every kind of diagnostic for every kind of uninstantiable template (which requires solving Halt).
So philosphically, your static_asserts in non-template methods should be possible to pass for some template arguments passed to the containing template class.
Things get murkier when you have a template method to a template class which is impossible to instantiate for certain template arguments to the template class. But that is going down a rabbit hole.
I am sufficiently uncertain about that last case that I avoid doing it, and instead use CRTP to conditionally have the method exist or not.
With C++2a, you might use requires:
void foo() requires (x != 0)
{
/*..*/
}
Demo
Static Assertion static_assert(bool_constexpr, message) performs compile-time assertion checking.
If bool_constexpr returns true, this declaration has no effect.
Otherwise a compile-time error is issued, and the text of message, if
any, is included in the diagnostic message.
Your code is static_assert(0,"Fail") Because of that 0 it will assert. But, if the bool expresion depends on a template parameter (or a function parameter), it has no value at compile time (unless you use a default value), and can not assert.
static_assert(x,"Fail") may assert if the compiler knows that x= false. Using B<0> b is not enough for the compiler. The assertion is done inside foo(). If this member is used, which means that this member function is instantiated, then the compiler does assert.
Can I put static_assert in class method if I never call this method?
A static assert declaration may appear at namespace and block scope
(as a block declaration) and inside a class body (as a member
declaration)
So, yes, you can.
Why template functions do not show in the LLVM-IR if the function is not called, when emitting LLVM IR from a c++ code,
unlike other types of functions (int, float...) which will be present in the llvm ir
example: the following function func1 doesnt show in llvm ir
template <class tmp>
tmp func1 () {
// ...
}
But this function func2 always shows in llvm ir
int func2 () {
// ...
}
This is because your templates are not functions: they are function templates. They are not compiled until it is instantiated with arguments. For example, take this code:
template<typename T>
T foo() { /* ... */ }
That will nor output any code.
But this on the other hand:
template<typename T>
T foo() { /* ... */ }
int test() {
return foo<int>();
}
Will output the code for both test and foo<int>.
You can also manually instantiate a template like this:
template int foo<int>();
This has to do with how C++ templates work. Since the compiler doesn’t know what tmp is until you call the function (or more precisely, when you instantiate it), it doesn’t know how to write code for it. For example, consider this template:
template <typename T>
T add(T left, T right) {
return left + right;
}
If T is an integer, then the function body is an integer add. If T's a double, it’s a floating-point add. If T’s a std::string, it’s a function call to std::string::operator+.
Since there are a lot of types in any C++ program, and many of them can be added, and pretty much every one is added in different ways, it cannot create the code for the function until it knows this type. If it tried to do it for all possible types T, you’d get a combinatorial explosion of possible implementations, almost all of which are never used. Your compile time and binary size would be huge for little if any benefit.
Things get slightly more complicated with class templates. An instantiation of a class template doesn’t actually need to instantiate all the functions if they aren’t called. Going back to our example, if we instead wrote:
template <typename T>
class Adder {
T add(T left, T right) {
return left + right;
}
};
Adder<int> a;
this still wouldn’t instantiate Adder<int>::add even though the compiler has all the information to know that add<int> is potentially interesting, because you don’t actually call or otherwise instantiate it.
I need a method(C++ 11) that is called for all types except one.
template<typename T>
void method(T& value)
{
...
}
template<>
void method(std::string& value)
{
...
}
Is it possible to do something like this? If not, is there other alternatives than using typeid at runtime?
there are several ways to do this, so you can use most convenient one:
// way 1
template<typename T,
typename std::enable_if<!std::is_same<T,std::string>::value>::type* = nullptr>
// way 2
void method(T& value)
{
static_assert(!std::is_same<T,std::string>::value,"std::string is not accepted");
...
}
// way 3
template <>
void method<std::string>(std::string&) = delete;
As for me, I find 3 to be the most convenient one for filtering out specific type, and 1 for filtering out some subset of types
You do not need template specialization. And neither SFINAE (enable_if). When you get caught up in template functions it's easy to forget that functions can overload. Just create a non-templated overload and that will be preffered when passing an argument of that exact type (a better solution is presented in the linked article):
template<typename T>
void method(T& value)
{
// ...
}
void method(std::string& value)
{
// ...
}
I strongly recommend reading this article Why Not Specialize Function Templates? by Herb Sutter.
Moral #1: If you want to customize a function base template and want
that customization to participate in overload resolution (or, to
always be used in the case of exact match), make it a plain old
function, not a specialization. And, if you do provide overloads,
avoid also providing specializations.
But you fall in the Moral #2:
But what if you're the one who's writing, not just using, a function
template? Can you do better and avoid this (and other) problem(s) up
front, for yourself and for your users? Indeed you can:
Moral #2: If you're writing a function base template, prefer to
write it as a single function template that should never be
specialized or overloaded, and then implement the function template
entirely as a simple handoff to a class template containing a static
function with the same signature. Everyone can specialize that -- both
fully and partially, and without affecting the results of overload
resolution.
The whole explanation is in the article.
This is basic template specialization, look at code sample below.
Code sample (based on your code):
template<typename T>
void method(T& value) {
//
}
template<>
void method<std::string>(std::string& value) {
//
}
This means, when you call method with std::string parameter the second (specialized) method will be called. Otherwise if you do not want to have the second function, then you will have to use c++ type traits (answered in the other answer).
I have functions of this type:
type uniRndtype()
{
return typeValue;
}
and now I'm trying to wrap them inside another template function like this:
template<typename T>
T(* uniRndType(void))()
{
if (is_same<T, bool>::value)
{
return uniRndBool;
} else if (is_same<T, char>::value)
{
return uniRndChar;
} else
...
}
and calling it like this:
uniRndType<int>();
But I'm getting an error: "error: return value type does not match the function type"
because each return has a different type..
I there a way to make it work? Because from a runtime point of view I see no errors, only the compiler have problems.
The problem is that while the optimiser can eliminate dead code branches, the front-end (lexical, syntactic & semantic analysis) can't. Which means all code in a template instantiation must be valid. That is, even though in this:
if (is_same<T, bool>::value)
{
return uniRndBool;
}
the body will never be executed when T is char, it must still be valid C++ code. And of course it's not, because uniRndBool doesn't have the correct type.
You have two options: a hackish one which works in your particular case, and a generic one.
The hackish one is using reinterpret_cast<T(*)()> in all the return statements. For the correct T brach, it will be a no-op. The other branches will never be executed at runtime, so all will be fine.
The other solution is to use template specialisation. Since it's a bad idea to specialise function templates, you could use the well-known "delegate to class" trick:
template <class T>
struct uniRndTypeHelper;
template <>
struct uniRndTypeHelper<bool>
{
static bool (*get())() { return uniRndBool; }
};
template <>
struct uniRndTypeHelper<char>
{
static char (*get())() { return uniRndChar; }
};
template<typename T>
T(* uniRndType(void))()
{
return uniRndTypeHelper<T>::get();
}
template <typename T> T (*uniRndType())()
{
//else
...
}
template <> bool (*uniRndType())()
{
return uniRndBool;
}
template <> char (*uniRndType())()
{
return uniRndChar;
}
That's all.
edit: In principle, we must do like #Angew. but it's little troublesome
This won't work because when the compiler expands the template method for a given type the method has to be valid. Your type, T, needs to be compatible with all the return types listed, eg bool, char, etc. As I mentioned in the comments, if you passed in a std::string you wouldn't expect the method to work, would you?
One way around this is to use template specialization to indicate what you want for each type.
Compiler needs to know what types will be used by functions/methods at compile time. At this point you must instantiate this template function with types which it may receive as template parameter, like #ikh wrote here.
But, if you are using template class with template methods, you have 2 ways:
1) Simply write realization of each template method in .h file (right in the place where you declaring template class body) instead of prototypes only;
2) Or after declaring prototypes in .h file you need to instatiate this template class with template parameters which it may receive.
Is there a way to require a templates type to have properties?
For example:
template <typename T, typename U>
void foo()
{
U a,b;
bool truthiness = T()(a,b);
if (truthiness)
// do something
}
So, how would I require that T have the operator()(U a, U b) defined, that returns a specific type? Is this possible? (I know it is in d, but I'm not sure about c++).
ps. if duck typing is wrong here, let me know, I believe it is correct, but I'm not sure.
Your syntax is wrong, considering your intent. Since T is a type, T(1, 2) would construct a temporary object of type T using a two-parameter constructor. If you wanted to call Ts operator () you'd have to вo something like
T()(1, 2);
assuming a call through a temporary works for your purposes.
If T had no such operator (), the code would simply fail to compile. I'd actually say that one big benefit of template code is that it "works" as long as the syntax is valid (i.e. the very duck-typing you are talking about), i.e. there's no need to further restrict it by requiring the operator () be present.
Of course, in my example it might actually make sense, since for T = void (*)(int, int) the code would be syntactically valid, but would result in a function call through a null pointer. But again, that's specific to my version of the code, and I don't know what specific object of type T you want to apply your operator () to.
Having said that, it is worth nothing that Boost library has quite a few features that allows one to check such properties and use them for branching in template meta-programming and/or in static assertions.
By simple expressing the template then you require for T to have operator()(int, int). It will not compile if it doesn't.
However if you are creating an API and want to inform the user of the API that they have passed in an incompatible type then you need to create a type trait which detects the operator and you can specialise the function to discriminate on that fact and create a static_assert to indicate the fact.
If you have access to decltype, you can roll your own check relatively easily.
template <class T, class U> class check_same_type_t;
template <class T> class check_same_type_t<T, T> { };
template <class T, class U>
void foo()
{
U a,b;
check_same_type_t<bool, decltype(T()(a, b))> check;
bool truthiness = T()(a,b);
if (truthiness) ;
// do something
}
Which enables the following:
struct A {
bool operator()(int, int) { return true; }
};
struct B {
int operator()(int, int) { return 1; }
};
int
main()
{
foo<A, int>(); // will compile
foo<B, int>(); // won't compile
}
Just make sure that this what you really want. Forcing a generic algorithm to use a specific type may potentially come back to bite you. If a type is implicitly convertible to bool, why is it unsatisfactory to use in your condition?