为什么奇怪的重复模板模式 (CRTP) 有效

why Curiously Recurring Template Pattern (CRTP) works

本文关键字:模式 CRTP 有效 为什么      更新时间:2023-10-16

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

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

例如

 template< typename T >
 class Base
 {
    ...
 };
 class Derived : public Base< Derived >
 {
    ...
 };

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

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

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

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

在CRTP的情况下,这一点在这里:

Base<Derived>

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

template <class>
struct Foo { };
struct Undefined;
Foo<Undefined> myFoo;

因此,只要Base的定义不需要Derived是完整的,一切都会起作用。

CRTP 被命名为重复出现,因为在

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

类模板Base在类Derived上实例化,该类继承自类Base<Derived>,而类又是类模板Base实例化在继承Base<Dervied> Derived ...等等。

上面Derived的名称在其自己的定义中使用,在尚未完全定义的上下文中,因此,这使得Derived成为不完整的类型。 Base<Derived> 正在实例化在当时不完整的类型 Derived 上,所以这就是递归结束的地方,因为Base不知道Derived反过来又从Base<Derived>继承。

public Base< Derived >

在这里,Derived仅指用于Base内部T的字体名,仅此而已。您当然可以获得无限递归,但这完全取决于您如何在Base中使用TT本身只是一种类型,就像任何其他类类型一样,类型本身实际上并不执行任何操作。