没有引用书籍,任何人都可以通过代码示例对 CRTP
进行很好的解释吗?
最佳答案
简而言之,CRTP就是当一个类A
有一个基类,它是类 A
的模板特化本身。例如
template <class T>
class X{...};
class A : public X<A> {...};
它是奇怪地重复出现,不是吗? :)
现在,这给了你什么?这实际上给出了 X
template 能够成为其特化的基类。
例如,您可以像这样创建一个通用单例类(简化版)
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 也可以)。
假设您只想提供运算符 <
为你的类(class),但自动运营商==
为了他们!
你可以这样做:
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/56939863/