Since you mention passing specializations of pairs to the class template:
template<typename... Pairs>
struct VectorOfMaps {
std::tuple<std::map<
typename Pairs::first_type
, typename Pairs::second_type
>...> tuple;
};
This is effectively using std::pair
as a type-list -- you could use something like template<typename T, typename U> struct pair { using first_type = T; using second_type = U; };
just as well.
It is possible to pass the types without the a pair as well, but this requires some metacomputations. A possible solution:
// First argument is accumulator, supposed to be an empty tuple
template<typename Acc, typename... T> struct compute_tuple
{
// Only triggered when the primary template is instantiated, which should
// only happen if sizeof...(T) is odd -- it's possible to assert on that
// instead, too.
static_assert( !sizeof(Acc), "An even number of arguments is required" );
};
// Recursive case
template<typename... Acc, typename First, typename Second, typename... Rest>
struct compute_tuple<std::tuple<Acc...>, First, Second, Rest...>
: compute_tuple<std::tuple<Acc..., std::map<First, Second>>, Rest...> {};
// Terminal case
template<typename Acc>
struct compute_tuple<Acc> { using type = Acc; };
template<typename... T>
struct VectorOfMaps {
/*
* You can assert that sizeof...(T) is even here; it might be more
* helpful than an error deeper inside compute_tuple.
*/
using tuple_type = typename compute_tuple<std::tuple<>, T...>::type;
tuple_type tuple;
};