4

次のコードでは:

template <typename T>
class CRTP
{
public:
};

template <int I, typename T>
class CRTPInt
{
public:
};

template <template <typename> class T>
class Derived : public T<Derived<T>>
{
public:
};

void main()
{
Derived<CRTP> foo;
Derived<CRTPInt<2>> foo2;
}

CRPTInt を記述して、テンプレート化されたパラメーターを渡すことができるようにするにはどうすればよいですか?

ありがとう、

ジム

4

1 に答える 1

4

CRTP パターンは通常、静的ポリモーフィズムmixin (パラメーター化された) 動作を有効にするために使用されます。2 つの選択肢を説明するには、最初に一般的なテンプレートを定義すると便利です

template
<
        typename Derived
>
class enable_down_cast
{
private:
        // typedefs

        typedef enable_down_cast Base;

public:
        Derived const* self() const
        {
                // casting "down" the inheritance hierarchy
                return static_cast<Derived const*>(this);
        }

        // write the non-const version in terms of the const version
        // Effective C++ 3rd ed., Item 3 (p. 24-25)
        Derived* self()
        {
                return const_cast<Derived*>(static_cast<Base const*>(this)->self());
        }

protected:
        // disable deletion of Derived* through Base*
        // enable deletion of Base* through Derived*
        ~enable_down_cast() = default; // C++11 only, use ~enable_down_cast() {} in C++98
};

次に、必要な動作のタイプのインターフェイス クラス テンプレートを定義します。

template<typename FX>
class FooInterface
:
    // enable static polymorphism
    public enable_down_cast< FX >
{
private:
    // dependent name now in scope
    using enable_down_cast< FX >::self;

public:
    // interface
    void foo() { self()->do_foo(); }

protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~IFooInterface() = default; // C++11 only, use ~IFooInterface() {} in C++98/03
};

このインターフェースのさまざまな実装を取得するには、単純に、それぞれが不思議なことに繰り返されるテンプレート パラメーターFooInterfaceとして派生するさまざまなクラスを定義します。

class FooImpl
:
    public FooInterface< FooImpl > 
{
private:
    // implementation
    friend class FooInterface< FooImpl > ;
    void do_foo() { std::cout << "Foo\n"; }
};

class AnotherFooImpl
:
    public FooInterface< AnotherFooImpl > 
{
private:
    // implementation
    friend class FooInterface< AnotherFooImpl >;
    void do_foo() { std::cout << "AnotherFoo\n"; }
};

別の方法は、インターフェイスのさまざまな実装をパラメーター化することです。今回は、クラス テンプレートはtemplate-template パラメーターと非型パラメーターの両方に依存します。

template<template<int> class F, int X>
class BarInterface
:
    public enable_down_cast< F<X> >
{
private:
    // dependent name now in scope
    using enable_down_cast< F<X> >::self;

public:
    // interface
    void bar() { self()->do_bar(); }    

protected:
    // disable deletion of Derived* through Base*
    // enable deletion of Base* through Derived*
    ~BarInterface() = default; // C++11 only, use ~BarInterface() {} in C++98/03
};

実装は別のクラス テンプレートであり、それ自体と非型パラメーターの両方を引数として使用してインターフェイスから派生します。

template< int X >
class BarImpl
:
    public BarInterface< BarImpl, X > 
{
private:
    // implementation
    friend class BarInterface< ::BarImpl, X >;
    void do_bar() { std::cout << X << "\n"; }    
};

これはあなたがそれらを呼び出す方法です:

int main()
{
    FooImpl f1;         
    AnotherFooImpl f2;
    BarImpl< 1 > b1;
    BarImpl< 2 > b2;

    f1.foo();
    f2.foo();
    b1.bar();
    b2.bar();

    return 0;
}

あなたの質問のクラスは、この一般的なパターンに完全には適合しません。DerivedCRTP のような動作をさせたい場合は、次のいずれかを実行できます。

class Derived1
: 
   public CRTP< Derived1 > 
{

};

template<int I>
class Derived2
: 
   public CRTPInt< Derived2, I >
{

};

更新: https://stackoverflow.com/a/11571808/819272からの議論に基づいて、元の回答は Visual Studio 2010 でのみコンパイルされ、Microsoft 固有の移植性のない機能のために gcc ではコンパイルされないことがわかりました。たとえば、self()関数 fromはその派生クラスの (テンプレート) 依存名であるため、明示的なディレクティブenable_down_castなしでは表示されません。usingさらに、適切なレベルの保護を備えたデフォルトのデストラクタを追加しました。最後に、元のクラスの名前を に変更enable_crtpしましenable_down_castた。これは、コンパイラが動的ポリモーフィズムに対して自動的に行うことを、静的ポリモーフィズムに対して手動で有効にするためです。

于 2012-07-18T17:56:53.153 に答える