テンプレートが受け取ることができる引数の種類を正確に指定できますか? たとえば、 class または class を拡張するクラスでのみインスタンス化できるテンプレートを作成したいと思いますA
。Java では、ジェネリックは次の方法でこれをサポートします。
class B<T extends A> { }
C++ のテンプレートで同様のことを実現できますか?
template <typename T (?)> class B { }
テンプレートが受け取ることができる引数の種類を正確に指定できますか? たとえば、 class または class を拡張するクラスでのみインスタンス化できるテンプレートを作成したいと思いますA
。Java では、ジェネリックは次の方法でこれをサポートします。
class B<T extends A> { }
C++ のテンプレートで同様のことを実現できますか?
template <typename T (?)> class B { }
あなたはとでこれを行うことができstatic_assert
ますis_base_of
:
#include <type_traits>
template<typename T> class D {
static_assert(std::is_base_of<A, T>::value, "must be derived from A");
};
または、次を使用できますenable_if
:
#include <type_traits>
template<typename T, typename = void> class D;
template<typename T> class D<T, typename std::enable_if<std::is_base_of<A, T>::value>::type> {
};
C ++ 03の場合、ブーストを使用できます。Boost.TypeTraitsis_base_of
から、Boost.StaticAssertから、Boost.EnableIfから。static_assert
enable_if
これには 2 つの方法があります。
まず、as 条件で使用する非表示のダミー テンプレート パラメーターを使用std::enable_if
しstd::is_base_of<A, T>::value
ます。後者の式が に評価される場合false
、ネストされたtype
は に存在しませんstd::enable_if
。オーバーロードされた関数でこれを使用していた場合、SFINAE は「置換の失敗はエラーではない」ことを意味し、問題のオーバーロードは実行可能な関数のセットから削除されます。ただし、この状況では、呼び出しに一致する他のクラス テンプレートがなく、コンパイル時エラーが発生します。
SFINAE は非常に微妙なメカニズムであり、間違えやすいです。たとえば、異なる SFINAE 条件を持つ複数のクラス特殊化がある場合、それらがすべて重複していないことを確認する必要があります。そうしないと、あいまいさが生じます。
2 つ目は、クラスの本体内で簡単static_assert
に実行できます。std::is_base_of<A,T>::value
この方法の利点は、SFINAE 方法よりも読みやすいエラー メッセージを指定できることです。欠点は、常にエラーが発生し、この特定のテンプレートを黙って抑制して別のテンプレートを選択できないことです。しかし、全体として、この方法はあなたの場合に推奨されると思います。
#include<type_traits>
class A {};
class C: public A {};
class D {};
// first alternative: SFINAE on hidden template parameter
template
<
typename T,
typename /* dummy */ = typename std::enable_if<
std::is_base_of<A, T>::value
>::type
>
class B
{
};
// second alternative: static_assert inside class
template
<
typename T
>
class E
{
static_assert(std::is_base_of<A, T>::value, "A should be a base of T");
};
int main()
{
B<A> b1;
B<C> c1;
//B<D> d1; // uncomment this line to get a compile-time error
E<A> b2;
E<C> c2;
//E<D> d2; // uncomment this line to get a compile-time error
return 0;
}
コメントで指摘されているように、適切な C++11 コンパイラ (VC++ 2010 以降、gcc 4.5 以降) または Boost または TR1 ライブラリを使用して<type_traits>
機能を取得できます。ただし、 は にstd::is_base_of<A, A>::value
評価されtrue
ますが、古いものは に評価されることに注意boost::is_base_of<A, A>::value
してくださいfalse
。