1. ホーム
  2. c++

[解決済み】CRTP(Curiously Recurring Template Pattern)とは何ですか?)

2022-04-08 08:30:42

質問

について、本を参照することなく、どなたか良い説明をお願いします。 CRTP をコード例付きで教えてください。

どのように解決するのですか?

要するに、CRTPとは、あるクラスが A のテンプレート特化である基底クラスがあります。 A そのものです。例

template <class T> 
class X{...};
class A : public X<A> {...};

それは 不思議と繰り返されるんですよね(笑)。

さて、これで何がわかるでしょうか。これは実際に X テンプレートは、その特殊化のための基本クラスとなる能力を備えています。

例えば、次のような汎用シングルトン・クラス(簡易版)を作ることができます。

template <class ActualClass> 
class Singleton
{
   public:
     static ActualClass& GetInstance()
     {
       if(p == nullptr)
         p = new ActualClass;
       return *p; 
     }

   protected:
     static ActualClass* p;
   private:
     Singleton(){}
     Singleton(Singleton const &);
     Singleton& operator = (Singleton const &); 
};
template <class T>
T* Singleton<T>::p = nullptr;

さて、任意のクラスを作るために A をシングルトン化するには、次のようにします。

class A: public Singleton<A>
{
   //Rest of functionality for class A
};

というわけで、お分かりいただけたでしょうか?シングルトンテンプレートは、任意の型に対するその特殊化を想定しています。 X から継承されます。 singleton<X> を含む、そのすべての (public, protected) メンバにアクセスできるようになります。 GetInstance ! CRTPには、他にも便利な使い方がある。例えば、あなたのクラスに現在存在する全てのインスタンスをカウントしたいが、このロジックを別のテンプレートにカプセル化したい場合(具象クラスのアイデアは非常にシンプルです - 静的変数を持って、ctorsで増分し、dtorsで減分します)。練習としてやってみてください。

もう一つ、Boostの便利な例を紹介しよう(どのように実装されたかはわからないが、CRTPでも可能)。 演算子 < を使用し、自動的に演算子 == を使用します。

というようなことができます。

template<class Derived>
class Equality
{
};

template <class Derived>
bool operator == (Equality<Derived> const& op1, Equality<Derived> const & op2)
{
    Derived const& d1 = static_cast<Derived const&>(op1);//you assume this works     
    //because you know that the dynamic type will actually be your template parameter.
    //wonderful, isn't it?
    Derived const& d2 = static_cast<Derived const&>(op2); 
    return !(d1 < d2) && !(d2 < d1);//assuming derived has operator <
}

これで、次のように使うことができます。

struct Apple:public Equality<Apple> 
{
    int size;
};

bool operator < (Apple const & a1, Apple const& a2)
{
    return a1.size < a2.size;
}

今、あなたは明示的に演算子を提供していない == に対して Apple ? しかし、あなたはそれを持っている!?と書くことができます。

int main()
{
    Apple a1;
    Apple a2; 

    a1.size = 10;
    a2.size = 10;
    if(a1 == a2) //the compiler won't complain! 
    {
    }
}

これは、演算子を書くだけなら書く量が減るように見えるかもしれません。 == に対して Apple が、想像してみてください。 Equality を提供するだけでなく == しかし > , >= , <= などです。そして、これらの定義を マルチプル クラスを作成し、コードを再利用することができます。

CRTPは素晴らしいものです :) HTH