什么是奇怪的重复模板模式(CRTP)?

新手上路,请多包涵

在不参考一本书的情况下,任何人都可以通过代码示例为 CRTP 提供一个很好的解释吗?

原文由 Alok Save 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 520
2 个回答

简而言之,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> 继承,因此它的所有(公共的、受保护的)成员都可以访问,包括 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!
    {
    }
}

This could seem that you would write less if you just wrote operator == for Apple , but imagine that the Equality template would provide not only == 但是 > , >= , <= 等等。您可以将这些定义用于 多个 类,重用代码!

CRTP 是一个很棒的东西 :) HTH

原文由 Armen Tsirunyan 发布,翻译遵循 CC BY-SA 4.0 许可协议

CRTP 是一种实现编译时多态性的技术。这是一个非常简单的例子。 In the below example, ProcessFoo() is working with Base class interface and Base::Foo the derived object’s foo() method, which is what you aim与虚方法有关。

http://coliru.stacked-crooked.com/a/2d27f1e09d567d0e

 template <typename T>
struct Base {
  void foo() {
    (static_cast<T*>(this))->foo();
  }
};

struct Derived : public Base<Derived> {
  void foo() {
    cout << "derived foo" << endl;
  }
};

struct AnotherDerived : public Base<AnotherDerived> {
  void foo() {
    cout << "AnotherDerived foo" << endl;
  }
};

template<typename T>
void ProcessFoo(Base<T>* b) {
  b->foo();
}

int main()
{
    Derived d1;
    AnotherDerived d2;
    ProcessFoo(&d1);
    ProcessFoo(&d2);
    return 0;
}

输出:

 derived foo
AnotherDerived foo

原文由 Chenna V 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏