Reputation: 123263
Does it make any sense to write code like this?
template<bool X>
double foo(double x){
return (X) ? moo(x) : bar(x);
}
I know that there are better ways to implement this example, but I wonder, if it is safe in general to assume that the compiler will identify dead code and instantiates this as
double foo<true>(double x){return moo(x);}
double foo<false>(double x){return bar(x);}
Upvotes: 2
Views: 986
Reputation: 5065
The thing to keep in mind here is templates are different from language features like generics in languages like C#.
It is a fairly safe simplification to think of templates as an advanced preprocessor that is type aware. This is the idea behind Template metaprogramming (TMP) which is basically compile time programming.
Much like the preprocessor templates are expanded and the result goes through all of the same optimization stages as your normal logic.
Here is an example of rewritting your logic in a style more consistent with TMP. This uses function specialization.
template<bool X>
double foo(double x);
template<>
double foo<true>(double x)
{
return moo(x);
}
template<>
double foo<false>(double x)
{
return bar(x);
}
TMP was actually discovered as a happy accident and is pretty much the bread and butter of the STL and Boost.
It is turing complete so you can do all sorts of computation at compile time.
It is lazily evaluated so you could implement your own compile time asserts by putting invalid logic in a specialization of a template that you don't want to be used. For example if I were to comment out the foo<false>
specialization and tried to use it like foo<false>(1.0);
the compiler would complain, although it would be perfectly happy with foo<true>(1.0);
.
Here is another Stack Overflow post that demonstrates this.
Further reading if interested:
Upvotes: 1
Reputation: 27673
...it is safe in general to assume that the compiler will identify dead code and instantiates this as
double foo<true>(double x){return moo(x);} double foo<false>(double x){return bar(x);}
From a pedantic perspective, the answer is no. What really happens is you will end up with two functions that look like this:
template <>
double foo<true>(double x) {
return (true) ? moo(x) : bar(x);
}
template <>
double foo<false>(double x) {
return (false) ? moo(x) : bar(x);
}
Each of these functions will be optimized with the rather obvious dead code elimination optimization. You end up with the same result, but there is an intermediate step.
There is a different technique for doing what you want which has a few advantages. You can rely on C++ overloading and a helper type called std::integral_constant
to make it 100% impossible to compile in the conditional expression.
double foo(double x, std::true_type) {
return moo(x);
}
double foo(double x, std::false_type) {
return bar(x);
}
Upvotes: 0
Reputation:
I specified "noinline" inorder to make it more obvious, and i got the value via cin instead of using a constant value to make sure compiler doesnt remove the function completly.
As you can see, both < true > and < false > have their own functions.
true => +0x1780
false => +0x1790
Template functions always have their own function based on the template argument
Upvotes: 1