C++ 如何将参数包转换为std::tuple以外的内容?

C++ 如何将参数包转换为std::tuple以外的内容?,c++,template-meta-programming,boost-mpl,C++,Template Meta Programming,Boost Mpl,最好用一个例子来解释: 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, typen

最好用一个例子来解释:

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 = ???
};
模板
结构一对
{
使用TupleOfArgs=std::tuple;
使用TupleOfPairs=std::tuple;
};
模板
结构二对
{
使用TupleOfArgs=std::tuple;
使用TupleOfPairs=std::tuple;
};
模板
结构NPairs
{
使用TupleOfArgs=std::tuple;
//使用TupleOfPairs=???
};
OnePair用一对定义一个元组。 TwoPairs使用两对定义元组

如何在NPairs中定义TupleOfPairs,以便将参数包转换为std::tuple of pairs

通过std库可以实现这一点吗?可能使用boost::mpl

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

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

static constexpr auto get_tuple(){
constexpr auto N=sizeof…(Args);
静态断言(N%2==0);
使用ArgsTuple=std::tuple;
自动执行=[](标准::索引_序列){
返回std::tuple<
//Is从0变为N/2,表示第i对
std::对。。。
>{};
};
返回impl(std::make_index_sequence{});
}
使用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;
};
模板
结构ZipPairs;
模板
struct ZipPairs{using type=PairsTuple;};
模板
结构ZipPairs
{
使用type=typename-ZipPairs<
std::tuple,Ts..>::type;
};
模板
结构NPairs
{
静态断言(sizeof…(Args)%2==0);
使用TupleOfArgs=std::tuple;
使用TupleOfPairs=typename-ZipPairs::type;
};

很好的解决方案。顺便说一句,我不能让它在vs2017上工作。@Gils,C++20模板化的lambda肯定不会。我不记得什么时候元编程支持在VS中得到了真正的提升,但它的其余部分可能会与lambda一起工作,分离到一个不同的函数。当然,它不会。但是我接受了你的建议,试着把lambda拿出来做一个函数。我得到了
'NPairs::get_tuple':返回“auto”的函数在定义之前不能使用
错误。我没有在上面花太多时间。递归解决方案对我来说更容易使用,因为我使用的是C++11。谢谢你的回答。我真的很喜欢它。@Gils,啊,这个代码段依赖于C++14返回类型的推导。当然,您可以将其重构为与C++11兼容的东西,但递归方法可能更具可读性。这是一个不错的解决方案。我试图用boost::mpl::list替换std::tuple,但由于某些原因,它不起作用。我得到以下错误:
错误:模板参数的数量错误(21,应该至少为0)
。知道哪里出了问题吗?我想你不应该像处理元组那样直接处理MPL模板参数,而是应该使用诸如
boost::MPL::insert
boost::MPL::push_back
之类的元函数。(看起来,
mpl::list
并不是真正的可变变量,但有一堆伪默认参数,可能是因为它最初是C++03/用于C++03兼容性。)而且
mpl::list
不支持
push_-back
。有很多方法可以让
mpl::list
工作,但是
mpl::vector
的翻译更直接:非常感谢您的解释。你的例子很有帮助。很抱歉没有早点回复,我花了一些时间才回到那个问题上来。
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;
};