我有一个这样的构造:
template<typename... Ts>
struct List {}
typedef List<char,List<int,float,List<int,unsigned char>>,List<unsigned,short>> MyList;
我想基本上将它展平为一个列表。什么是最好的方法?我想如果我摆弄它的时间足够长,我可以用递归来做一些事情,但有些事情告诉我应该有更好的方法。
作为上述树的结果,我想要的应该类似于:
typedef List<char,int,float,int,unsigned char,unsigned,short> FlattenedList;
这是我的第一次尝试:
template<typename... Ts>
struct List{};
template<typename... Ts>
struct FlattenTree{
typedef List<Ts...> Type;
};
template<typename... Ts, typename... Us, typename... Vs>
struct FlattenTree<Ts...,List<Us...>,Vs...>{
typedef typename FlattenTree<Ts..., Us..., Vs...>::Type Type;
};
但这会导致此错误:error C3515: if an argument for a class template partial specialization is a pack expansion it shall be the last argument
rici 在这里指出了MSVC2013 抱怨的内容,所以这里没有编译器错误:
§ 14.8.2.5(从类型推导模板参数)第 5 段列出了不能推导模板参数的上下文。相关的是列表中的最后一个:
— A function parameter pack that does not occur at the end of the parameter-declaration-clause.
更新:
我想可以在最后放入一个虚拟参数,继续将第一个参数移动到末尾,或者如果它是 List 则将其扩展到前面,并专注于第一个参数是我的虚拟参数以停止递归。不过,对于编译器来说,为了展平列表似乎需要做很多工作。
namespace Detail{
struct MyMagicType {};
template<typename T, typename... Ts>
struct FlattenTree{
typedef typename FlattenTree<Ts..., T>::Type Type;
};
template<typename... Ts>
struct FlattenTree<MyMagicType,Ts...>{ //termination case
typedef List<Ts...> Type;
};
template<typename... Ts, typename... Us>
struct FlattenTree<List<Ts...>, Us...>{
typedef typename FlattenTree<Ts..., Us...>::Type Type;
}; //expand Ts to front because they may hold more nested Lists
}
template<typename... Ts>
struct FlattenTree{
typedef typename Detail::FlattenTree<Ts...,Detail::MyMagicType>::Type Type;
};
这适用于 MSVC2013,但我认为这不是最好的方法,因为我需要一个虚拟类型并且它给编译器带来了很多负载。我想将它与包含 500 多个元素的列表一起使用。