Ive never used the C ++ 0x variable template function, but the following code compiles in g ++ 4.5:
template <typename... Args> struct tuple; template <typename T, typename... Args> struct tuple<T, Args...> { T value; tuple<Args...> inner; }; template <typename T> struct tuple<T> { T value; };
However, initializing them ... is strange, because we need to nest the internal values:
int main() { tuple<int> n1 = { 23 }; tuple<int, float> n2 = { 42, { 0.5f } }; tuple<std::string, double, int> n3 = { "hello, world", { 3.14, { 97 } } }; }
Retrieving values ββis, of course, a little tedious. The simplest method is perhaps to create a template for the get<N>() function.
But we cannot implement get directly, since function templates cannot be partially specialized. Either we need to use SFINAE (read: boost::enable_if ), or we need to delegate the actual get function to a type that can be partially specialized.
Later I did the last. But first, we need another trait of the auxiliary type: nth_type , which returns the corresponding return type of the get function:
template <unsigned N, typename... Args> struct nth_type; template <unsigned N, typename T, typename... Args> struct nth_type<N, T, Args...> : nth_type<N - 1, Args...> { }; template <typename T, typename... Args> struct nth_type<0, T, Args...> { typedef T type; };
Easy-Peasy. It simply returns the type n th in the type list.
Now we can write our get function:
template <unsigned N, typename... Args> inline typename nth_type<N, Args...>::type get(tuple<Args...>& tup) { return get_t<N, Args...>::value(tup); }
As I said, this simply delegates the task. No, biggie. In practice, we probably want to have a different overload for const tuples (but then in practice we would use the existing tuple type).
Now for the kill, followed by a light salad:
template <unsigned N, typename... Args> struct get_t; template <unsigned N, typename T, typename... Args> struct get_t<N, T, Args...> { static typename nth_type<N, T, Args...>::type value(tuple<T, Args...>& tup) { return get_t<N - 1, Args...>::value(tup.inner); } }; template <typename T, typename... Args> struct get_t<0, T, Args...> { static T value(tuple<T, Args...>& tup) { return tup.value; } };
And here it is. We can verify this by printing some values ββin our previously defined variables:
std::cout << get<0>(n1) << std::endl; // 23 std::cout << get<0>(n2) << std::endl; // 42 std::cout << get<0>(n3) << std::endl; // hello, world std::cout << get<1>(n2) << std::endl; // 0.5 std::cout << get<1>(n3) << std::endl; // 3.14 std::cout << get<2>(n3) << std::endl; // 97
Man, his funny messing around with variable patterns.