奇异重现模板模式

奇异重现模板模式（curiously recurring template pattern，CRTP）是C++模板编程时的一种惯用法（idiom）：把派生类作为基类的模板参数。更一般地被称作F-bound polymorphism，是一类。
历史.
1980年代作为被提出。于1995年称之为CRTP。在当时的早期C++模板超编程已经有所出现。
一般形式.
<syntaxhighlight lang="cpp">
// The Curiously Recurring Template Pattern (CRTP)
template<class T>
class Base
class Derived : public Base<Derived>
</syntaxhighlight> 
静态多态.
C++语言的多态，原本是用虚函数来实现的，属于动态多态。安德烈·亚历山德雷斯库在中提出了奇异重现模板模式，并称之为静态多态（static polymorphism）。
<syntaxhighlight lang="cpp">
template <class T> 
struct Base
struct Derived : Base<Derived>
</syntaxhighlight>
基类模板利用了其成员函数体（即成员函数的实现）在声明之后很久都不会被实例化（实际上只有被调用的模板类的成员函数才会被实例化），并利用了派生类的成员函数（通过）。
在上例中，Base<Derived>::interface()，虽然是在struct Derived之前就被声明了，但未被编译器实例化直至它被实际调用，这发生于Derived声明之后，此时Derived::implementation()的声明是已知的。
这种技术获得了类似于虚函数的效果，并避免了动态多态的代价。也有人把CRTP称为“模拟的动态绑定”。
这种模式广泛用于Windows ATL与WTL库，以及Boost.Iterator，Boost.Python或者Boost.Serialization等库中。
考虑一个基类，没有虚函数，则它的成员函数能够调用的其它成员函数，只能是属于该基类自身。当从这个基类派生其它类时，派生类继承了所有未被覆盖（overridden）的基类的数据成员与成员函数。如果派生类调用了一个被继承的基类的函数，而该函数又调用了其它成员函数，这些成员函数不可能是派生类中的派生或者覆盖的成员函数。也就是说，基类中是看不到派生类的。但是，基类如果使用了CRTP，则在编译时派生类的覆盖的函数可被选中调用。这效果相当于编译时模拟了虚函数调用但避免了虚函数的尺寸与调用开销（VTBL结构与方法查找、多继承机制）等代价。但CRTP的缺点是不能在运行时做出动态绑定。
不通过虚函数机制，基类访问派生类的私有或保护成员，需要把基类声明为派生类的友元（friend）。如果一个类有多个基类都出现这种需求，声明多个基类都是友元会很麻烦。一种解决技巧是在派生类之上再派生一个accessor类，显然accessor类有权访问派生类的保护函数；如果基类有权访问accessor类，就可以间接调用派生类的保护成员了。这种方法被boost的多个库使用，如：Boost.Python中的def_visitor_access和Boost.Iterator的iterator_core_access。原理示例代码如下：
<syntaxhighlight lang="cpp">
template<class DerivedT> class Base
};
struct Derived : Base<Derived> // 派生类不需要任何特别的友元声明
</syntaxhighlight>
例子1：对象计数.
统计一个类的实例对象创建与析构的数据。可以轻松地利用CRTP实现:
<syntaxhighlight lang="cpp">
template <typename T>
struct counter
protected:
template <typename T> int counter<T>::objects_created( 0 );
template <typename T> int counter<T>::objects_alive( 0 );
class X : counter<X>
class Y : counter<Y>
</syntaxhighlight>
例子2：多态复制构造.
当使用多态时，常需要基于基类指针创建对象的一份拷贝。常见办法是增加clone虚函数在每一个派生类中。使用CRTP，可以避免在派生类中增加这样的虚函数。 
<syntaxhighlight lang="cpp">
// Base class has a pure virtual function for cloning
class Shape {
public:
};
// This CRTP class implements clone() for Derived
template <typename Derived>
class Shape_CRTP : public Shape {
public:
// Nice macro which ensures correct CRTP usage
// Every derived class inherits from Shape_CRTP instead of Shape
Derive_Shape_CRTP(Square) {};
Derive_Shape_CRTP(Circle) {};
</syntaxhighlight>
This allows obtaining copies of squares, circles or any other shapes by codice_1.
例子3：不可派生的类.
一个类如果不希望被继承，类似于Java中的具有finally性质的类，这在C++中可以用虚继承来实现：
<syntaxhighlight lang="cpp">
template<typename T> class MakeFinally{
class MyClass:public virtual MakeFinally<MyClass>{};//MyClass是不可派生类
//由于虚继承，所以D要直接负责构造MakeFinally类，从而导致编译报错，所以D作为派生类是不合法的。
class D: public MyClass{};
//另外，如果D类没有实例化对象，即没有被使用，实际上D类是被编译器忽略掉而不报错
int main()
MyClass var1;
// D var2; //这一行编译将导致错误，因为D类的默认构造函数不合法
</syntaxhighlight>
例子4：std::enable_shared_from_this.
在C++标准库头文件codice_2中，codice_3类封装了可被共享使用的指针或资源。一个被共享的对象不能直接把自身的原始指针（raw pointer）codice_4传递给codice_3的容器对象（如一个std::vector），因为这会生成该被共享的对象的额外的共享指针控制块。为此，codice_3 API提供了一种类模板设施codice_7，包含了成员函数codice_8，从而允许从this创建一个codice_3对象。
<syntaxhighlight lang="cpp">
class mySharedClass:public std::enable_shared_from_this<mySharedClass>{
public:
int main()
</syntaxhighlight>
其它语言.
在Java与.NET Framework中，常见把一个类作为泛型超类或interface的类型参数。例如，下述Java类实现了标准库中的泛型界面codice_10:
<syntaxhighlight lang="java">
public class Item implements Comparable<Item> {
 private String name;
 @Override
 public int compareTo(final Item other) {
 return name.compareTo(other.name);
</syntaxhighlight>
这保证了编译时不会比较codice_11与其它不是codice_11的对象如codice_13。与C++不同，Java类不能使用不同的类型参数扩展一个超类两次，也不能用不同的类型参数实现同一个interface两次。这是由于Java实用了类型擦除处理泛型。例如，上例的class codice_11不能同时实现codice_15与codice_16。详见。