As a type container, the standard provides you with std::tuple
and -- as bogdan commented -- you can access the type elements using std::tuple_element
.
using foo = std::tuple<char, short&, const long&&, long long>;
template <int N>
typename std::tuple_element<N,foo>::type bar(){/*...*/}
Even if std::tuple_element
did not exist, you could easily build your own:
/// We want a metafunction to accept an index N into our type list LIST
template <unsigned N, typename LIST> struct
tuple_element;
/// Specialization for the case where N==0
template <template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<0,LIST_T<T,ELMS...>> {
using type = T; // just take the first type from the list
};
template <unsigned N, template <typename ...> class LIST_T,typename T,typename...ELMS> struct
tuple_element<N,LIST_T<T,ELMS...>> {
/// fallback for N>0: delegate the result type recursively until N->0
using type = typename tuple_element<N-1,LIST_T<ELMS...>>::type;
};
// create a convenience wrapper for the template
template <unsigned N, typename LIST> using
type_at = typename tuple_element<N, LIST>::type;
Now you can define your type list, e.g. like so:
using foo = std::tuple<char, short&, const long&&, long long>;
And you can easily access it's elements using type_at<N, foo>
:
static_assert(std::is_same< type_at<0,foo>, char>::value,"error");
static_assert(std::is_same< type_at<1,foo>, short&>::value,"error");
static_assert(std::is_same< type_at<2,foo>, const long&&>::value,"error");
static_assert(std::is_same< type_at<3,foo>, long long>::value,"error");
template <int N>
type_at<N,foo> bar(){/*...*/}