テンプレートの定義が間違っていると思います。どちらの場合も、正確な再帰をトリガーしています。コンパイラーがコンパイラー内のスタックオーバーフローで停止することを期待していましたが、別のエラーが生成されました...
are_same可変個引数テンプレートの実装は次のようになります。
template <class... Args> // base (optional to declare the template)
struct are_same;
template <class A, class B, class... Args> // recursion
struct are_same<A,B,Args...> {
static const bool value = is_same<A,B>::value && are_same<A,Args...>::value;
};
template <class A, class B> // stop condition
struct are_same<A,B> {
static const bool value = is_same<A,B>::value;
};
このrecursionステップでは、引数のリストから 1 つの引数が削除されていることに注意してください。これにより、解決する新しい問題は元の問題の縮小版になります。このタイプのテンプレート メタプログラミングは再帰と非常に関連しており、同じ規則が適用されます。再帰を使用できるようにするには、各再帰ステップが確実にソリューションに近づくようにする必要があります。この特定のケースでは、N 個の潜在的に同じ型のリストが与えられた場合、各ステップは問題を N-1 個の型が同じかどうかを見つけることに軽減します。
are_same代わりに、問題の縮退バージョンを停止条件として (前のものを置き換えて) 使用できます。
template <class A>
struct are_same<A> {
static const bool value = true;
};
これは、単一の型が *are_same* であるかどうかを尋ねるのは実際には意味がないという意味で退化していますが、異なるメタプログラミング タスクに対しては適切である可能性があります。
依存しない別の潜在的により効率的なアルゴリズム (上記の再帰ステップでコンパイラーがテンプレートのインスタンス化を回避するかどうかはわかりません) は次のis_sameようになります。
template <class... Args>
struct are_same;
template <class A, class... Args>
struct are_same<A,A,Args...> { // recursion
static const bool value = are_same<A,Args...>::value;
};
template <class A, class B, class... Args>
struct are_same<A,B,Args...> { // cut, A and B are not the same
static const bool value = false;
};
template <class A>
struct are_same<A> { // end of recursion
static const bool value = true;
};
この場合、コンパイラは 2 つの型が同じ場合は必ずステップよりも を優先するrecursionため、内部cutでチェックする必要はありません。is_same同時に、コンパイラがcutステップに入った場合、型リストの残りを処理する必要はありません。答えは既にわかっているからです。