如何将ParameterPack转换为std::tuple之外的其他内容



可以用一个例子来更好地解释:

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用一对定义元组。TwoPairs定义了一个包含两对元组的元组。

如何在NPairs中定义TupleOfPairs,以便将参数包转换为std::元组?

用std库有可能做到这一点吗?也许有助推::mpl?

两个答案,都很棒。@chris使用迭代方法,而@aschepler使用递归解决方案。就我个人而言,我发现递归解决方案更容易遵循。

您可以使用熟悉的索引序列技巧,但大小只有一半(示例(:

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());

如果您没有C++20,您将不得不将lambda扩展为一个函数,而不是使用漂亮的内联索引序列扩展,但核心仍然是函数。使用类型列表而不是std::tuple,它可能也会更干净一些,但它是可行的。

这里有一种使用递归助手的简单方法:

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;
};