テンプレートが受け取ることができる引数の種類を正確に指定できますか? たとえば、 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_assertenable_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。