奇怪的循环模板模式(CRTP)是什么?
没有提到一本书,任何人都可以提供一个很好的解释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 };
所以你看到了? 单例模板假定其任何typesX的特化将从singleton<X>
inheritance,因此将拥有所有(公共的,受保护的)成员可访问的,包括GetInstance
! 还有其他有用的CRTP。 例如,如果要计算当前为您的类存在的所有实例,但希望将此逻辑封装在单独的模板中(具体类的想法非常简单 – 有一个静态variables,在ctors中增量,在dtors中递减)。 尝试做一下练习!
另一个有用的例子,提升(我不知道他们是如何实现的,但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, isnit 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; }
现在,你还没有提供明确的运营商==苹果? 但你有它! 你可以写
int main() { Apple a1; Apple a2; a1.size = 10; a2.size = 10; if(a1 == a2) //the compiler won't complain! { } }
如果你只为苹果公司编写operator ==,那么你可能会写得更less,但想象一下,Equality模板不仅会提供==,而且还会提供>,= =,<=等等。你可以将这些定义用于多个类,重用代码!
CRTP是一个奇妙的东西:) HTH
在这里你可以看到一个很好的例子。 如果使用虚拟方法,程序将知道在运行时执行什么操作。 实现CRTP编译器是在编译时决定的! 这是一个很好的performance!
template <class T> class Writer { public: Writer() { } ~Writer() { } void write(const char* str) const { static_cast<const T*>(this)->writeImpl(str); //here the magic is!!! } }; class FileWriter : public Writer<FileWriter> { public: FileWriter(FILE* aFile) { mFile = aFile; } ~FileWriter() { fclose(mFile); } //here comes the implementation of the write method on the subclass void writeImpl(const char* str) const { fprintf(mFile, "%s\n", str); } private: FILE* mFile; }; class ConsoleWriter : public Writer<ConsoleWriter> { public: ConsoleWriter() { } ~ConsoleWriter() { } void writeImpl(const char* str) const { printf("%s\n", str); } };
正如注意:
CRTP可以用来实现静态多态性(类似于dynamic多态但是没有虚函数指针表)。
#pragma once #include <iostream> template <typename T> class Base { public: void method() { static_cast<T*>(this)->method(); } }; class Derived1 : public Base<Derived1> { public: void method() { std::cout << "Derived1 method" << std::endl; } }; class Derived2 : public Base<Derived2> { public: void method() { std::cout << "Derived2 method" << std::endl; } }; #include "crtp.h" int main() { Derived1 d1; Derived2 d2; d1.method(); d2.method(); return 0; }
输出将是:
Derived1 method Derived2 method