I have recently started using C++11, and I have read in a tutorial about variadic templates. I have understood that we can define a variadic template like this
// example class that uses variadic template
template<typename ...Args> struct mtuple;
But how can I handle the template arguments of the mtuple
class (i.e. how would the get<int>(mtuple_obj)
look like?)?
What get<1>(t)
looks like will depend on the implementation of mtuple
. A typical implementation recusively inherits from a type that holds each argument, so mtuple<A,B,C>
inherits from TupleHead<A>
(which has a member of type A
) and also inherits from TupleTail<B,C>
. TupleTail<B,C>
inherits from TupleHead<B>
(which has a member of type B
) and TupleTail<C>
. TupleTail<C>
inherits from TupleHead<C>
(which has a member of type C
.)
Now, if you give each base class an integer parameter too:
mtuple<A,B,C>
inherits from TupleHead<0,A>
and TupleTail<1,B,C>
TupleTail<1,B,C>
inherits from TupleHead<1,B>
and TupleTail<2,C>
TupleTail<2,C>
inherits from TupleHead<2,C>
Now it's relatively simple to write get<1>
, because the mtuple
has a single unique base class of type TupleHead<1,B>
which can be obtained by an upcast, then return the B
member of that base class.
[Edit: get<1>(m)
needs to know the type B
that corresponds to the tuple element with index 1, for that you use something like std::tuple_element
which also relies on the recursive inheritance hierarchy described above and uses partial specialization to get the TupleHead<1,T>
base class with index 1, then determines the parameter T
in that partial specialization, which gives B
in my example.]
Many of the techniques used with variadic templates are functional programming techniques, such as operating on the first element of the template parameter pack, then recursively doing the same thing on the remainder of the pack, until you've processed all the elements. There aren't many things you can do with a template parameter pack directly except count its size (with sizeof...
) or instantiate another template with it, so the usual approach is to instantiate another template that separates the pack Args
into ArgHead, ArgsTail...
and processes the head, then recursively do the same to ArgsTail
There is no simple mechanism to iterate over the values of a variadic template. But this can be done recursively. Here is an example:
template<typename T, typename... Args>
void print_values(const char *s, T value, Args... args)
{
while (*s) {
if (*s == '%' && *(++s) != '%') {
std::cout << value;
++s;
print_values(s, args...);
return;
}
cout << *(s++);
}
}
So, if I call print_values("%d %d %d", 1, 2, 3)
I get this recursion tree:
print_values("%d %d %d", 1, 2, 3) // value -> 1, args... -> 2,3
print_values("%d %d", 2, 3) // value -> 2, args... -> 3
print_values("%d", 3) // value -> 3, args... -> NULL
print_values("") // value -> NULL, args... -> NULL
I recursively call print_values()
even when *s == 0 to detect extra arguments
Source: http://en.wikipedia.org/wiki/Variadic_templates
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