2

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);}
Zitrax
  • 19,036
  • 20
  • 88
  • 110
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • 4
    The "how" is probably a bit tedious to answer, but the compiler will certainly do what you expect. That's absolutely basic optimization. – Columbo Oct 30 '15 at 20:19
  • @Columbo so the question is either too trivial or too broad ;) however, I am happy with the answer – 463035818_is_not_an_ai Oct 30 '15 at 20:25
  • The optimization has very little to do with templates here -- the compiler will also optimize `inline double foo(bool b, double x) { return b ? moo(x) : bar(x); }` if it can see the value of `b`. – Travis Gockel Oct 30 '15 at 20:25
  • @TravisGockel yes, but I prefer to make it visible in the code that only half of it will be compiled – 463035818_is_not_an_ai Oct 30 '15 at 20:27
  • You could check the disassembly of your optimized build to see what happens. – Neil Kirk Oct 30 '15 at 20:33
  • 1
    @tobi303 I understand where you're coming from, but that's not actually what happens here. Both sides of the conditional operator are compiled -- they just happen to get optimized out most of the time. If you're going for *cannot be compiled* (as in: the compiler can only see `moo(x)` or `bar(x)`, depending on `X`), there are other techniques you can use. If that's what you want, I can provide a more long-form example. – Travis Gockel Oct 30 '15 at 20:39
  • @TravisGockel sorry that was maybe a misunderstanding, i will need both verions (`true` and `false`) and just wanted to make sure that using template doesnt introduce overhead (because I could as well simply use `moo(x)` and `bar(x)` alone) – 463035818_is_not_an_ai Oct 30 '15 at 21:04

3 Answers3

1

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. enter image description here

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

user2596732
  • 47
  • 1
  • 8
1

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:

  1. Modern C++ Design
  2. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond
  3. Effective C++
Community
  • 1
  • 1
Matthew Sanders
  • 4,875
  • 26
  • 45
0

...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);
}
Travis Gockel
  • 26,877
  • 14
  • 89
  • 116
  • You can also look at my answer for the version without overloads. C++ does not allow you to **partially special** a **function template**, but you can **fully** specialize one. – Matthew Sanders Oct 30 '15 at 21:13