79

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++ について話しているのです。

4

10 に答える 10

77

C++11 を使用する場合は、この目的static_assertで withを使用できます。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");

        // ...
    }
}
于 2014-04-08T11:00:21.493 に答える
44

「暗黙のうちに」が正解です。テンプレートは、そのコンパイル方法により、効果的に「ダック タイピング」シナリオを作成します。テンプレート型の値に対して必要な関数を呼び出すことができます。受け入れられる唯一のインスタンス化は、そのメソッドが定義されているものです。例えば:

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 ページ テンプレートのコンパイル時エラーが発生します。

于 2008-09-23T17:15:53.987 に答える
36

他の誰かが言及したように、C++0x はこれを言語に組み込みます。それまでは、テンプレートの制約に関するBjarne Stroustrupの提案をお勧めします。

編集:Boostには独自の代替手段もあります。

Edit2: C++0x から概念が削除されたようです。

于 2008-09-23T17:12:18.210 に答える
18

何もしない IFoo にガードタイプを置くことができます。それが Foo の T にあることを確認してください:

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}
于 2008-09-23T17:19:55.913 に答える
9

ブーストをチェック

Boost コンセプト チェック ライブラリ (BCCL)

コンセプト チェック ライブラリを使用すると、提案された C++ 言語拡張のスタイルで明示的なステートメントとコンセプトのチェックを追加できます。

于 2008-09-23T17:08:13.257 に答える
2

あなたはそれを行うことができます。ベース テンプレートを作成します。Private コンストラクターのみを持つようにします。次に、許可するケースごとに特殊化を作成します (または、許可されていないリストが許可されているリストよりもはるかに小さい場合は、その逆を行います)。

コンパイラは、プライベート コンストラクターでバージョンを使用するテンプレートをインスタンス化することを許可しません。

この例では、int と float を使用したインスタンス化のみが許可されています。

template<class t> class FOO { private: FOO(){}};

template<> class FOO<int>{public: FOO(){}};

template<> class FOO<float>{public: FOO(){}};

短くてエレガントな方法ではありませんが、可能です。

于 2008-09-30T12:03:58.163 に答える
2

並べ替え。IFoo* に static_cast した場合、呼び出し元が IFoo* に割り当て可能なクラスを渡さない限り、テンプレートをインスタンス化することはできません。

于 2008-09-23T17:09:18.700 に答える
1

暗黙的にのみ。
実際に呼び出されるメソッドで使用するメソッドはすべて、テンプレート パラメーターに適用されます。

于 2008-09-23T17:07:24.397 に答える
-1

CRTP パターン (Curiously Recursive Template Pattern) を見てください。静的継承をサポートするように設計されています。

于 2008-12-04T18:33:55.683 に答える