我有一个这样的构造:
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
里奇指出hereMSVC2013 抱怨什么,所以这里没有编译器错误:
§ 14.8.2.5(从类型推导模板参数)第 5 段列出了无法推导模板参数的上下文。相关的是列表中的最后一个:
— A function parameter pack that does not occur at the end of the parameter-declaration-clause.
Update:
我想人们可以在最后放入一个虚拟参数,继续将第一个参数移动到末尾,或者如果它是列表,则将其扩展到前面,并专门将第一个参数作为我的虚拟参数来停止递归。不过,对于编译器来说,仅仅为了压平列表似乎需要做很多工作。
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 多个元素的列表一起使用。