====== 2012.05.03 - variadic template homework ======
{{ :blog:2012:05:03:isoneof_andrei.png|template wheel - based on a true code :)}}
finally i got some spare time and finish watching recordings from [[http://channel9.msdn.com/Events/GoingNative/GoingNative-2012|Going Native 2012]]. during one of the [[wp>Andrei Alexandrescu]]'s [[http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Variadic-Templates-are-Funadic|presentations on variadic templates]] viewers were given a homework to be done: implementing [[wp>cartesian product]] of the given template arguments, to exercise variadics a little.
since the task is originally underspecified, let us stick to the number values, instead of (usual) types (for the sake of outputting) and assume the simple notion of generating result by directly printing each pair on the screen, instead of "saving" it as a type for later expansion (saves extra code to print-out the result in test/toy app). of course all of the computations are done in the compile time (except of printing itself ;)).
so first let us define the interface, that will be used:
template
void expand(void)
{
Cart::template go();
}
it takes sequence of numbers as the argument and prints them out using //Cart// template class and its //go()// template method. they both take expanded arguments (i.e. values) lists. this enables us to iterate over the twice-expanded arguments.
having this done, we implement the most generic class, that will be used to stop compile-time iteration:
template
struct Cart
{
template
static void go() { }
};
now comes the fun part -- iteration over the list. first we'll define previous template's specialization, that splits arguments into head (//H//) and tail of "T" elements (//Ts// -- "s" is for plural):
template
struct Cart
{
};
now //go()// template (static) method is being implemented. what it does is to call helper sub-class (also variadic template), that will creates elements for all arguments, paired with the current one. class is called //X//, in short. next step is to call instance of own class, but with different arguments -- implementation moves to the next class-template argument:
template
struct Cart
{
template
static void go()
{
X::go();
Cart::template go();
}
};
note that last line -- //Cart<**Ts...**>::template go<**Us...**>()//. we move to the next argument with //Ts// BUT keep the original, full list //Us// for //go()//, so that next argument can be paired up with the full list of elements again!
now it's time for //X// to appear -- this is simple metaprogram, that prints first argument of the class it is part of and then another arguments, given as its arguments. so the full //Cart//'s class specialization looks like this:
template
struct Cart
{
template
static void go()
{
X::go();
Cart::template go();
}
template
struct X
{
static void go() { }
};
template
struct X
{
static void go()
{
cout<::go();
}
};
};
example output for:
expand<1,2,66>();
gives (i.e. prints):
1:1
1:2
1:66
2:1
2:2
2:66
66:1
66:2
66:66
clean, short and simple! :) here is the full source of the {{:blog:2012:05:03:vt_cp.cpp|cartesian product}} implementation.