CRTP:一个继承 以自己为模板参数的模板类 的类
什么是CRTP?
The curiously recurring template pattern (CRTP) is a C++ idiom in which a class X
derives from a class template instantiation using X
itself as template argument.
翻译过来叫做”奇特的递归模板模式“,具体介绍请参看维基百科https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
简单的表述一下,类B继承了一个以B作为模板参数的的模板类A,这就是CRTP,代码如下:
template<typename T> class A
{} class B :public A<B> {}
CRTP有什么用?
在网上看了很多文章,大体上分为两种表述,一类是实现静态多态,二类是类计数器,单例模式等等
但仔细想想,这些看似花哨的功能到底作用在何处呢,似乎好像都可以通过其他方式来实现
CRTP核心特性
在我看来,CRTP最核心的特性有两点:
1、为不同的子类保留了不同的基类信息
2、让基类提前知道子类的信息,以做一些泛型操作
这两点听起来似乎有点不好理解,下面做一些解释
1、为不同的子类保留了不同的基类信息
class C :public A<C> {}
还是在上述例子的基础上,此时有一个C类,在普通的继承模式下,B和C共享了同一个基类信息,而在此模式下,B和C保留了各自不同的特化基类A<B>和A<C>
在此基础上,与类相关的操作得以很容易的实现,最典型就是类的静态成员相关的操作,比如引用计数,再比如com思想中的uid的实现
template<typename T> class A { public: A() {++m_nCounter; } ~A() {--m_nCounter; } public: void printCount() { cout << m_nCounter << endl; } private: static int m_nCounter; }; template <typename T> int A<T>::m_nCounter = 0; class B :public A<B> { public: B() { }; ~B() { }; void printCountOfB() { printCount(); } }; class C :public A<C> { public: C() { }; ~C() { }; public: void printCountOfC() { printCount(); } };
如上所示,B和C可以持有自己独立的类计数。
2、让基类提前知道子类的信息,以做一些泛型操作
最典型的例子,通过CTRP来实现单例模式的复用,在父类中通过模板参数预留接口。同时,该例子中也使用到了特性1,即让每个基类蕴含了一个独特的单例对象
template <typename T> class Singleton { public: static T& Instance() { static T s_Instance; return s_Instance; } Singleton(const Singleton& rhs) = delete; Singleton& operator = (const Singleton& rhs) = delete; Singleton(const Singleton&& rhs) = delete; Singleton& operator = (const Singleton&& rhs) = delete; protected: Singleton() = default; ~Singleton() = default }; class SingletonInstance : public Singleton<SingletonInstance> { friend class Singleton<SingletonInstance>; ... }