私は可変個引数テンプレートを多用する C++11 の大規模なソフトウェア インフラストラクチャに取り組んでいます。私の質問は次のとおりです。このアプローチのスケーラビリティは何ですか? まず、可変個引数テンプレートが取ることができる引数の数に上限はありますか? 第二に、多くの引数が使用されている場合 (さらに、テンプレート化されたメソッドのさまざまな実装につながるこれらの引数の多くの組み合わせ) は、最先端のコンパイラでコードの肥大化が大きな問題になりますか?
1 に答える
特定のコンパイラ (Linux では g++ 4.8.1) のテンプレート パラメーターの数に制限があるかどうかを調べてみようと思いました。次のテストケースを使用しました。
template <int I>
struct this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life {};
template <int Depth, typename... T>
struct A
{
using e = this_is_a_ridiculously_long_struct_name_youd_never_use_in_real_life<Depth>;
A() {};
A<Depth - 1, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, e, T...> a;
};
template <typename... T>
struct A<0, T...>
{
};
int main()
{
A<899> a;
}
テンプレートの再帰の深さの制限は、g++ ではデフォルトで 900 に設定されているため、899 パラメーターが表示されます。途方もなく長い構造体名は、リンカが処理するには大きすぎるシンボルを生成できるかどうかを確認するために使用されます。これについては、後で詳しく説明します。
テスト ケースで何が起こっているのかがわからない場合のために、基本的に のインスタンス化ごとに、A
20 個のテンプレート パラメーターを追加するメンバー変数を作成します。再帰を停止するために、部分的な特殊化が使用されます。最終的にA<0, ...>
は、18000 のテンプレート パラメータの領域のどこかにあります。
私が見つけたのは、g ++がこれをうまく処理したことです。考えるのにかなり時間がかかり、かなりのメモリを使用しましたが、テンプレートのパラメーターの数を増やすだけでは失敗することはありませんでした。Clang 3.1 は、テンプレートの再帰の深さが十分に設定されていれば (つまり 900)、問題なくこれを処理しました。
さらに、マングルされたシンボル名は確かに巨大になりますが、どちらも壊すことも使用することもできませんでしnm
たld
。(Linux/Itanium マングリング スキームは置換を使用するため、同じ型の繰り返されるテンプレート パラメーターは型名全体を繰り返さず、むしろマークされますS0
。S1
) ELFシンボルの長さの制限ですが、おそらく他の誰かがそのような制限が存在するかどうかを知っています.
結論として、少なくとも Linux の g++ と clang では、テンプレート パラメーターの数に実質的な制限はないようです。
コードの肥大化に関する質問の 2 番目の部分については、特にコンパイラの最適化が関与すると、言うのは非常に困難です。可変個引数テンプレートを使用して再帰を行うのは簡単ですが、コンパイラが中間型を取り除くのも簡単です。私はそれを試してみることを提案することしかできません。