为什么奇怪的重复模板模式(CRTP)的工作原理

时间:2018-04-07 15:34:58

标签: c++ templates crtp

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

  

ATL中的Microsoft CRTP实现是由Jan Falkin于1995年独立发现的,他偶然从派生类派生了一个基类。 Christian Beaumont首先看到了Jan的代码,并且最初认为它不可能在当时可用的Microsoft编译器中编译。根据这一启示确实确实有效,克里斯蒂安以整个ATL和WTL设计为基础。

例如,

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

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

我理解为什么以及什么时候可以使用它。但我想知道编译器如何以这种方式工作。因为在我的脑海里它不应该由于无休止的递归而起作用:class Derived继承自Base&lt; Derived&gt;,其中Derived是继承自Base&lt;派生&gt;,其中派生......等等。 能否请您从编译器的角度逐步解释它是如何工作的?

3 个答案:

答案 0 :(得分:2)

递归定义的类型并不常见:链表也是递归的。它的工作原理是因为在周期的某一点你不需要完成类型,你只需要知道它的名字。

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

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

Base<Derived>

Base实例化Derived 要求Derived完成,只知道它是类类型。即,以下工作正常:

template <class>
struct Foo { };

struct Undefined;

Foo<Undefined> myFoo;

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

答案 1 :(得分:1)

public Base< Derived >

此处,Derived仅指T BaseT使用的类型名称,它就是全部。您当然可以获得无限递归,但这完全取决于您在Base内使用T的方式。 xLarge本身只是一种类似任何其他类型的类型,类型本身并没有实际做任何事情。

答案 2 :(得分:0)

CRTP被命名为 recurring ,因为在

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

类模板Base在类Derived上实例化,该类继承自类Base<Derived>,而类Base又在{上实例化了类模板Derived {1}},它继承了Base<Dervied> ...等。

在尚未完全定义的上下文中,上面的名称Derived用于其自身的定义,因此,这使Derived成为不完整类型。 Base<Derived>正在实例化为类型Derived的那一刻不完整,因此这是递归结束的地方,因为Base无法知道DerivedBase<Derived>继承。