为什么 Curiously Recurring Template Pattern (CRTP) 有效

why Curiously Recurring Template Pattern (CRTP) works

我遇到了很多关于 CRTP 是什么的解释,但没有解释它为什么起作用。

The Microsoft Implementation of CRTP in ATL was independently discovered, also in 1995 by Jan Falkin who accidentally derived a base class from a derived class. Christian Beaumont, first saw Jan's code and initially thought it couldn't possibly compile in the Microsoft compiler available at the time. Following this revelation that it did indeed did work, Christian based the entire ATL and WTL design on this mistake.

例如,

 template< typename T >
 class Base
 {
    ...
 };

 class Derived : public Base< Derived >
 {
    ...
 };

我明白为什么以及什么时候可以使用它。但我想知道编译器是如何以这种方式工作的。因为在我看来,由于无休止的递归,它不应该工作:class Derived 继承自 Base< Derived >,其中 Derived 是 class 继承自 Base< Derived >,其中 Derived... 依此类推。

能否请您从编译器的角度逐步解释它是如何工作的?

public Base< Derived >

这里的Derived只是指在Base中用于T的一个typename,仅此而已。您当然可以获得无限递归,但这完全取决于您如何在 Base 中使用 TT 本身只是一种类似于任何其他 class 类型的类型,类型本身实际上并没有做任何事情。

Recursively-defined 类型并不罕见:链表也是递归的。它之所以有效,是因为在循环中的某一时刻,您不需要类型是完整的,您只需要知道它的名称。

struct LinkedNode {
    int data;
    LinkedNode *next; // Look ma, no problem
};

对于 CRTP,关键点在这里:

Base<Derived>

Derived实例化Base确实需要Derived才完整,才知道是class 类型。即,以下工作正常:

template <class>
struct Foo { };

struct Undefined;

Foo<Undefined> myFoo;

因此,只要Base的定义不需要Derived是完整的,一切正常。

CRTP 被命名为 recurring 因为在

class Derived: public Base<Derived> { ... }

class 模板 Base 在 class Derived 上实例化,它继承自 class Base<Derived>,即,反过来,class 模板 BaseDerived 上实例化,它继承了 Base<Dervied> ... 等等。

上面的名称 Derived 在它自己的定义中使用,在它尚未完全定义的上下文中,因此,这使得 Derived 成为 不完整类型。 Base<Derived> 正在类型 Derived 上实例化,该类型当时不完整,因此这是递归结束的地方,因为 Base 无法知道 Derived,在轮流继承自Base<Derived>.