Reputation: 643
It is better explained by an example:
template <typename T1, typename T2>
struct OnePair
{
using TupleOfArgs = std::tuple<T1, T2>;
using TupleOfPairs = std::tuple<std::pair<T1, T2>>;
};
template <typename T1, typename T2, typename T3, typename T4>
struct TwoPairs
{
using TupleOfArgs = std::tuple<T1, T2, T3, T4>;
using TupleOfPairs = std::tuple<std::pair<T1, T2>, std::pair<T3, T4>>;
};
template <typename... Args>
struct NPairs
{
using TupleOfArgs = std::tuple<Args...>;
// using TupleOfPairs = ???
};
OnePair defines a tuple with one pair. TwoPairs defines a tuple with two pairs.
How do I define TupleOfPairs in NPairs so it transforms the Parameter Pack to std::tuple of pairs?
Is it possible to achieve that with the std library? Maybe with boost::mpl?
Two answers, both great. @chris uses an iterative method while @aschepler uses a recursive solution. Personally, I found the recursive solution easier to follow.
Upvotes: 2
Views: 162
Reputation: 72271
Here's one straightforward way with a recursive helper:
template <typename PairsTuple, typename... Ts>
struct ZipPairs;
template <typename PairsTuple>
struct ZipPairs<PairsTuple> { using type = PairsTuple; };
template <typename... Pairs, typename T1, typename T2, typename... Ts>
struct ZipPairs<std::tuple<Pairs...>, T1, T2, Ts...>
{
using type = typename ZipPairs<
std::tuple<Pairs..., std::pair<T1, T2>>, Ts...>::type;
};
template <class... Args>
struct NPairs
{
static_assert(sizeof...(Args) % 2 == 0);
using TupleOfArgs = std::tuple<Args...>;
using TupleOfPairs = typename ZipPairs<std::tuple<>, Args...>::type;
};
Upvotes: 1
Reputation: 61900
You can use the familiar index sequence trick, but with half the size (live example):
static constexpr auto get_tuple() {
constexpr auto N = sizeof...(Args);
static_assert(N%2 == 0);
using ArgsTuple = std::tuple<Args...>;
auto impl = []<std::size_t... Is>(std::index_sequence<Is...>) {
return std::tuple<
// Is goes from 0 to N/2, representing Ith pair
std::pair<std::tuple_element_t<Is*2, ArgsTuple>, std::tuple_element_t<Is*2 + 1, ArgsTuple>>...
>{};
};
return impl(std::make_index_sequence<N/2>{});
}
using TupleOfArgs = decltype(get_tuple());
If you don't have C++20, you'll have to expand the lambda out to a function instead of being able to use the nice inline index sequence expansion, but the core still functions. It might also be a bit cleaner with a typelist instead of std::tuple
, but it's workable.
Upvotes: 2