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:
- Modern C++ Design
- C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond
- Effective C++