C#では、ジェネリックパラメーターとして使用できる型に制約を課すジェネリック型を定義できます。次の例は、一般的な制約の使用法を示しています。
interface IFoo
{
}
class Foo<T> where T : IFoo
{
}
class Bar : IFoo
{
}
class Simpson
{
}
class Program
{
static void Main(string[] args)
{
Foo<Bar> a = new Foo<Bar>();
Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
}
}
C++でテンプレートパラメータに制約を課す方法はありますか。
C++ 0xはこれをネイティブでサポートしていますが、現在の標準C++について話しています。
他の誰かが言ったように、C++ 0xはこれを言語に組み込んでいます。それまでは、 Bjarne Stroustrup の テンプレート制約の提案 をお勧めします。
Edit2: C++ 0xから概念が削除されました のように見えます。
C++ 11を使用する場合、この目的でstatic_assert
をstd::is_base_of
とともに使用できます。
例えば、
#include <type_traits>
template<typename T>
class YourClass {
YourClass() {
// Compile-time check
static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");
// ...
}
}
「暗黙的に」が正しい答えです。テンプレートは、コンパイル方法により「カモタイピング」シナリオを効果的に作成します。テンプレート型の値に対して必要な関数を呼び出すことができ、受け入れられるインスタンス化は、そのメソッドが定義されているものだけです。例えば:
_template <class T>
int compute_length(T *value)
{
return value->length();
}
_
int
を返すlength()
メソッドを宣言する任意の型へのポインターでこのメソッドを呼び出すことができます。したがって:
_string s = "test";
vector<int> vec;
int i = 0;
compute_length(&s);
compute_length(&vec);
_
...-notを宣言する型へのポインターではないlength()
:
_compute_length(&i);
_
この3番目の例はコンパイルされません。
これは、C++がインスタンス化ごとにテンプレート化された関数(またはクラス)の新しいバージョンをコンパイルするためです。そのコンパイルを実行するとき、型チェックの前に、テンプレートのインスタンス化をコードに直接、ほぼマクロのように置き換えます。それでもすべてがそのテンプレートで機能する場合、コンパイルが進行し、最終的に結果が得られます。何かが失敗する(_int*
_がlength()
を宣言しないなど)場合、恐ろしい6ページのテンプレートのコンパイル時エラーが発生します。
あなたは何もしないIFooにガードタイプを置くことができます、それがFooのTにあることを確認してください:
class IFoo
{
public:
typedef int IsDerivedFromIFoo;
};
template <typename T>
class Foo<T>
{
typedef typename T::IsDerivedFromIFoo IFooGuard;
}
チェックアウト ブースト
Boostコンセプトチェックライブラリ(BCCL)
コンセプトチェックライブラリにより、明示的なステートメントと concepts のチェックを 提案されたC++言語拡張 のスタイルで追加できます。
並べ替え。 IFoo *にstatic_castする場合、呼び出し側がIFoo *に割り当てることができるクラスを渡さない限り、テンプレートをインスタンス化することはできません。
暗黙的にのみ。
実際に呼び出されるメソッドで使用するメソッドは、テンプレートパラメーターに適用されます。
できます。基本テンプレートを作成します。プライベートコンストラクターのみを持つようにします。次に、許可する各ケースに特化を作成します(または、許可されていないリストが許可されているリストよりもはるかに小さい場合は、反対になります)。
コンパイラは、プライベートコンストラクターでバージョンを使用するテンプレートをインスタンス化することを許可しません。
この例では、intおよびfloatでのインスタンス化のみが許可されます。
template<class t> class FOO { private: FOO(){}};
template<> class FOO<int>{public: FOO(){}};
template<> class FOO<float>{public: FOO(){}};
短くエレガントな方法ではありませんが、可能です。