不参考书籍,任何人都可以通过代码示例为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还有其他有用的用途。例如,如果您要计算您的类当前存在的所有实例,但想将此逻辑封装在单独的模板中(具体类的想法很简单-拥有一个静态变量,ctor中的增量,dtor中的减量)。尝试做为练习!

对于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

关于c++ - 什么是好奇重复模板模式(CRTP)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57736062/

10-12 20:43