Template metaprogramming

From Cppwiki

Jump to: navigation, search

Template metaprogramming is a form of compile-time programming in C++, using template expressions. While a normal program would use variables of a certain type, in metaprogramming, types are variables. A metaprogram is very similar to the style of programming used in functional programming.

Functions in metaprogramming are called metafunctions. The simplest metafunction simply returns a value with no inputs; i.e. a constant. An integer constant function could be written thus:

template<typename T, T n>
struct int_ {
  static T const value = n;
  typedef T type;
};

We can then express constant types such as int_<int, 4> and int_<unsigned long, 42>.

std::cout << int_<int, 4>::value << '\n'; // prints 4

A simple metafunction with inputs might be one to add two ints. A first try at such a function might look like this:

template<typename T, T a, T b>
struct plus {
  static T const value = a + b;
  typedef T type;
};

Although this would indeed work as desired, it has a few problems. Firstly, 'a' and 'b' are required to be integral constants; plus<int_<int, 1>, int_<int, 2> > will not work. In this case one could write plus<int, int_<int, 1>::value, int_<int, 2>::value>, but the requirement to reduce all inputs to integral types quickly becomes a pain, particularly since plus<> might be specialised over types which cannot be represented as such.

Instead, metafunctions are written using inheritance. In a functional language, plus would probably be written as something equivalent to:

plus (a, b) = a + b

This effectively says that plus(a,b) is a+b; in C++, the closet equivalent is:

template<typename a, typename b>
struct plus : int_<typename a::type, a::value + b::value> {}

Here we state that plus<a,b> is-a int<a+b>. Other than the values being types instead of variables, this is effectively identical to the functional program.

Examples

A 'pair' metaclass, which returns a type storing two other types; plus<> is specialised such that plus(pair(a, b), pair(c, d)) = pair(a + c, b + d).

#include <iostream>
template<typename T, int n>
struct int_ {
  typedef T type;
  static const T value = n;
};
template<typename a, typename b>
struct plus : int_<typename a::type, a::value + b::value> {};
template<typename a, typename b>
struct pair {
  typedef a first;
  typedef b second;
};
template<typename af, typename as, typename bf, typename bs>
struct plus<pair<af, as>, pair<bf, bs> > :
  pair< plus<af, bf>,
        plus<as, bs>
  >
{};
int main() {
  typedef int_<int, 42> a;
  typedef int_<int, 3> b;
  typedef pair<int_<int, 1>, int_<int, 1> > pt;
  std::cout << plus<a, b>::value << '\n';
  typedef plus<pair<a, b>, pt> res;
  std::cout << res::first::value << ", " << res::second::value << '\n';
}

A mathematical power function can be computed at compile-time with template metaprogramming.

template< int base, unsigned exponent >
struct power {
    enum { value = base * power<base, exponent - 1>::value };
};
template< int base >
struct power<base,0> {
    enum { value = 1 };
};
Personal tools