質問
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 ではこれが言語に組み込まれています。それまでは、お勧めします ビャルネ・ストルストラップさんの テンプレート制約の提案.
編集2:みたいです 概念は 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();
}
このメソッドは、 length()
を返すメソッド int
. 。したがって:
string s = "test";
vector<int> vec;
int i = 0;
compute_length(&s);
compute_length(&vec);
...しかし、それを行う型へのポインタではありません ない 宣言する 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;
}
チェックアウト ブースト
ブースト コンセプト チェック ライブラリ (BCCL)
Concept Check ライブラリを使用すると、明示的なステートメントとチェックを追加できます。 概念 のスタイルで 提案された C++ 言語拡張.
ある意味。IFoo* に static_cast する場合、呼び出し元が IFoo * に割り当てられるクラスを渡さない限り、テンプレートをインスタンス化することはできません。
暗黙的にのみ。
実際に呼び出されるメソッド内で使用するメソッドはすべて、テンプレート パラメーターに適用されます。
できますよ。基本テンプレートを作成します。Private コンストラクターのみを持つようにします。次に、許可するケースごとに特殊化を作成します (または、禁止リストが許可リストよりはるかに小さい場合はその逆を行います)。
コンパイラでは、プライベート コンストラクターを含むバージョンを使用するテンプレートをインスタンス化することはできません。
この例では、int と float によるインスタンス化のみが許可されます。
template<class t> class FOO { private: FOO(){}};
template<> class FOO<int>{public: FOO(){}};
template<> class FOO<float>{public: FOO(){}};
短くてエレガントな方法ではありませんが、可能です。
CRTP パターン (Curiously Recursive Template Pattern) を見てください。これは、静的継承のサポートを支援するように設計されています。