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

Sou*_*ess 5 c++ templates crtp

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

微软在 ATL 中实现的 CRTP 也是在 1995 年由 Jan Falkin 独立发现的,他意外地从派生类派生了基类。Christian Beaumont,第一次看到 Jan 的代码,最初认为它不可能在当时可用的 Microsoft 编译器中编译。在发现它确实有效之后,Christian 将整个 ATL 和 WTL 设计基于这个错误。

例如,

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

 class Derived : public Base< Derived >
 {
    ...
 };
Run Code Online (Sandbox Code Playgroud)

我明白为什么以及何时可以使用它。但我想知道编译器是如何以这种方式工作的。因为在我的脑海中它不应该由于无休止的递归而起作用:类Derived继承自Base< Derived >,继承自的DerivedBase< Derived >在哪里,Derived......等等。

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

Que*_*tin 8

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

struct LinkedNode {
    int data;
    LinkedNode *next; // Look ma, no problem
};
Run Code Online (Sandbox Code Playgroud)

就 CRTP 而言,这一点如下:

Base<Derived>
Run Code Online (Sandbox Code Playgroud)

实例化forBase不需要Derived完整,只需要知道它是一个类类型即可Derived即,以下工作正常:

template <class>
struct Foo { };

struct Undefined;

Foo<Undefined> myFoo;
Run Code Online (Sandbox Code Playgroud)

因此,只要定义Base不要求Derived完整,一切就可以了。

  • @JimBalter我不知道为什么你必须如此敌对,而且我不知道如何以另一种方式重新表述我的答案。类型可以是完整的,也可以是不完整的,CRTP *总是*接收不完整的类型作为参数,仅此而已。以完全相同的方式,您可以形成一个指向不完整类型的指针,并在同一类型的定义中使用它,这样链表就可以工作。 (2认同)