Fun with C++ template metaprogramming, part II
27 Jan 2014In part I we discussed some basic constructs that could be built using C++ template metaprogramming. This time, we’re going to build up to doing more complicated things - building lists and operating on them.
How can we build a list in a C++ template? I decided to borrow a common idea from Lisp, a cons list
The idea is to essentially build a recursive structure so that each element of the list contains two values - the value at that point in the list, and the remaining list. Each list node holds a head
and a tail
, (or in Lisp jargon, car
and cdr
). In pseudo-code:
list a (list b (list c (list d ...)))
But then the question arises of how to terminate the list. The best way to do this is with some terminal marker or sentinel to indicate the last element, or the empty list. In Lisp, this could be nil
, or in Haskell a special constructor for the empty list []
. Again, in pseudo code, this is something like:
list a (list b (list c (list d (emptylist))))
Then to transate this to a C++ template, we can do the following:
So here we have a type that contains a list of int
. When we build the list, myList
, we’re building a type that represents the list [a, b, c, d]
. Not a runtime series of structs
, but a type that we can operate on at compile. For example, pulling the HEAD
of the list out can be achieved with:
Remember in part I, we built functions out of templates whose input were types. Now that we have a list in a type, we can write functions that operate on it, at compile.
To run a function over the list, say to calculate the sum:
Note again how I’ve used the pattern matching in template specialisation to define the different implementations for the recursive case and the base case in the SUM
definitions.
For something more interesting, how about map-reduce!
Here, MAP_REDUCE
is a function (template) that takes a LIST
, a unary function F
(again, a template) to map over the list and a binary function R
(also a template) to reduce the list to a single value (e.g. addition or minimum).
There are toy examples showing map reduce in action (such as summing the squares of a list, finding the minimum) in the git repository at tmp-play.
In the next section, I’ll be talking about more advanced operations, building up to what I originally set out to do - sort a list at compile time!