web-dev-qa-db-ja.com

テンプレートの制約C ++

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

59
Jorge Ferreira

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

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

Edit2: C++ 0xから概念が削除されました のように見えます。

34
luke

C++ 11を使用する場合、この目的でstatic_assertstd::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");

        // ...
    }
}
53
Venemo

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

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

36
Daniel Spiewak

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

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}
14
Eclipse

チェックアウト ブースト

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

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

8

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

2
Lou Franco

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

1
shoosh

できます。基本テンプレートを作成します。プライベートコンストラクターのみを持つようにします。次に、許可する各ケースに特化を作成します(または、許可されていないリストが許可されているリストよりもはるかに小さい場合は、反対になります)。

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

この例では、intおよびfloatでのインスタンス化のみが許可されます。

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

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

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

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

0
OldMan