如何将参数包转换成 std::tuple 以外的东西?

How to transform Parameter Pack into something else than 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::tuple 对?

是否可以使用 std 库来实现?也许 boost::mpl?

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

您可以使用熟悉的索引序列技巧,但大小减半 (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());

如果您没有 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;
};