fluter
fluter

Reputation: 13846

unpack a parameter pack of pairs into an array and a tuple

So i have a list of pairs where the first member is a constant integer and the second is a type, is there anyway to unpack it into an array of the first member and a tuple of the second members?

struct MA {}
struct MB {}
struct MC {}
template <int I, class T> struct MyPair{};

How can I make a template meta function such that it has these two members:

MyStruct<1, MA, 2, MB, 3, MC> {
     std::array<int, 3> arr = {1, 2, 3};
     using Tuple = std::tuple<MA, MB, MC>;
};

Upvotes: 3

Views: 530

Answers (1)

Evg
Evg

Reputation: 26362

Just define two helper metafunctions to get I and T:

template<class> struct GetFirst;
template<int I, class T> struct GetFirst<MyPair<I, T>> {
    static constexpr int value = I;
};

template<class> struct GetSecond;
template<int I, class T> struct GetSecond<MyPair<I, T>> {
    using type = T;
};

template<class... MyPairs>
struct MyStruct {
    std::array<int, sizeof...(MyPairs)> arr{GetFirst<MyPairs>::value...};
    using Tuple = std::tuple<typename GetSecond<MyPairs>::type...>;
};

//////////////////////////////////////////////////

using S = MyStruct<MyPair<1, MA>, MyPair<2, MB>, MyPair<3, MC>>;
static_assert(std::is_same_v<S::Tuple, std::tuple<MA, MB, MC>>);
assert((S{}.arr == std::array{1, 2, 3}));

You can't mix type and non-type parameters in a variadic template, so it's not possible to have

MyStruct<1, MA, 2, MB, 3, MC, ...>

without wrapping (int, Type) into a type.


As JeJo mentioned in a comment below, both metafunctions can be joined into a single one:

template<class> struct MyPairTraits;
template<int I, class T> struct MyPairTraits<MyPair<I, T>> {
    static constexpr int i = I;
    using Type = T;
};

Upvotes: 7

Related Questions