Here's another set of code with a convenience function return_type that you could use to access any type at a specific index in a varadic template list ... you could then adapt the call to return_type so that you get the first and the last arguments (i.e., the first argument will be at 0, and the last argument will be at sizeof...(TypeList)):
template<typename T> struct type_id_struct { typedef T type; T object_instance; }; template<int N, typename... TypeList> struct reduce {}; template<int N, typename T1, typename... TypeList> struct reduce<N, T1, TypeList...> { typedef typename reduce<N - 1, TypeList... >::type type; }; template<typename T1, typename... TypeList> struct reduce<0, T1, TypeList...> { typedef T1 type; }; //convenience function template<int N, typename... TypeList> type_id_struct<typename reduce<N, TypeList...>::type> return_type() { return type_id_struct<typename reduce<N, TypeList...>::type>(); }
Here's an example of using the convenience function return_type in actual code to determine the Nth template argument in a variadic template:
int main() { auto type_returned = return_type<2, int, double, char>(); std::cout << typeid(type_returned.object_instance).name() << std::endl; return 0; }
In this case, since the int template argument to return_type is 2, you'll get the char type as the output. Any number over 2 will cause an overflow that will create a compile rather than runtime error. As noted, you could adapt it so that it's wrapped inside a function in a structure that will allow you to access the types in the variadic template for that specific structure instance using the sizeof...(TypeList) - 1 applied to an enum. For instance:
template<typename... TypeList> struct an_object { enum { first = 0, last = (sizeof...(TypeList) - 1) }; template<int N> auto wrapper() -> decltype(return_type<N, TypeList...>()) { return return_type<N, TypeList...>(); } }; //...more code int main() { an_object<int, double, char> a; auto r_type1 = a.wrapper<an_object<int, double, char>::first>(); std::cout << typeid(r_type1.object_instance).name() << std::endl; auto r_type2 = a.wrapper<an_object<int, double, char>::last>(); std::cout << typeid(r_type2.object_instance).name() << std::endl; return 0; }
sizeof...(T)and in the specialization it is1 + sizeof...(T). You need to pass that number along to theanotherAmember of the specialization.