463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123263

How does the compiler optimize templates?

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

Answers (3)

Matthew Sanders
Matthew Sanders

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:

  1. Modern C++ Design
  2. C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond
  3. Effective C++

Upvotes: 1

Travis Gockel
Travis Gockel

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

user2596732
user2596732

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. 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

Upvotes: 1

Related Questions