私はこのような構造を持っています:
template<typename... Ts>
struct List {}
typedef List<char,List<int,float,List<int,unsigned char>>,List<unsigned,short>> MyList;
そして、基本的にそれを1つのリストにフラットにしたいと考えています。最善の方法は何ですか?十分に長くいじれば、再帰で何かを作ることができると思いますが、もっと良い方法があるはずだと何かが教えてくれます。
上記のツリーの結果として必要なものは、次のようになります。
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.
アップデート:
一番最後にダミーパラメーターを入れて、最初の引数を最後に移動し続けるか、リストの場合は前に展開し、最初のパラメーターがダミーであることに特化して再帰を停止できると思います。ただし、リストをフラット化するだけでも、コンパイラにとっては大変な作業のようです。
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 以上の要素を含むリストで使用したい。