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