我遇到了很多解释什么是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;,其中派生......等等。 能否请您从编译器的角度逐步解释它是如何工作的?
答案 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
Base
内T
使用的类型名称,它就是全部。您当然可以获得无限递归,但这完全取决于您在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
无法知道Derived
从Base<Derived>
继承。