I have a problem... I don't understand template metaprogramming.
The problem is, that I’ve read a lot about it, but it still doesn’t make much sense to me.
Fact nr.1: Template Metaprogramming is faster
template <int N> struct Factorial { enum { value = N * Factorial<N - 1>::value }; }; template <> struct Factorial<0> { enum { value = 1 }; }; // Factorial<4>::value == 24 // Factorial<0>::value == 1 void foo() { int x = Factorial<4>::value; // == 24 int y = Factorial<0>::value; // == 1 }
So this metaprogram is faster ... because of the constant literal.
BUT: Where in the real world do we have constant literals? Most programs I use react on user input.
FACT nr. 2 : Template metaprogramming can accomplish better maintainability.
Yeah, the factorial example may be maintainable, but when it comes to complex functions, I and most other C++ programmers can't read them.
Also, the debugging options are very poor (or at least I don't know how to debug).
When does template metaprogramming make sense?
Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled.
Code generationA quine is a special kind of metaprogram that produces its own source code as its output. Quines are generally of recreational or theoretical interest only.
Generics are used for metaprogramming in Ada. They are useful for abstract algorithms that share common properties with each other.
Metaprogramming is writing a program which outputs another program. This is something languages like Lisp are really good at. It is much easier to do in a language that supports real macros (not C++ macros, but rather ones that can manipulate the code they output) such as Ruby, Lisp, Scheme, etc.
Just as factorial is not a realistic example of recursion in non-functional languages, neither is it a realistic example of template metaprogramming. It's just the standard example people reach for when they want to show you recursion.
In writing templates for realistic purposes, such as in everyday libraries, often the template has to adapt what it does depending on the type parameters it is instantiated with. This can get quite complex, as the template effectively chooses what code to generate, conditionally. This is what template metaprogramming is; if the template has to loop (via recursion) and choose between alternatives, it is effectively like a small program that executes during compilation to generate the right code.
Here's a really nice tutorial from the boost documentation pages (actually excerpted from a brilliant book, well worth reading).
http://www.boost.org/doc/libs/1_39_0/libs/mpl/doc/tutorial/representing-dimensions.html
I use template mete-programming for SSE swizzling operators to optimize shuffles during compile time.
SSE swizzles ('shuffles') can only be masked as a byte literal (immediate value), so we created a 'mask merger' template class that merges masks during compile time for when multiple shuffle occur:
template <unsigned target, unsigned mask> struct _mask_merger { enum { ROW0 = ((target >> (((mask >> 0) & 3) << 1)) & 3) << 0, ROW1 = ((target >> (((mask >> 2) & 3) << 1)) & 3) << 2, ROW2 = ((target >> (((mask >> 4) & 3) << 1)) & 3) << 4, ROW3 = ((target >> (((mask >> 6) & 3) << 1)) & 3) << 6, MASK = ROW0 | ROW1 | ROW2 | ROW3, }; };
This works and produces remarkable code without generated code overhead and little extra compile time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With