我对如何编译CRTP感到困惑。如果我们有这样的事情:
template<class T>
class Base
{
};
class Derived : public Base<Derived>
{
};
为什么在编译期间没有类似的事情发生?
(X[Y]
表示X继承自Y)
声明Derived
个实例
Derived d;
d
正在扩展为模板和继承的无限复发
d[Base<Derived[Base<Derived[Base<Derived[Base<Derived[...]>]>]>]>]
为什么不发生这种情况?关于CRTP的所有教程只解释了你可以用它做什么,而不是在幕后发生的事情(至少含糊不清)。
答案 0 :(得分:7)
要理解的基本概念是模板的实例只是一个类。它根本没有任何其他类别。
如果您有典型的模板定义:
template<typename T> class Base;
然后是模板实例:
Base<int>
只是该名称的一类。它与int
无关,与int
完全没有任何关系。它不会以某种方式或以任何方式从中继承。
下一步:
class Derived;
template<typename T> class Base {};
Base<Derived> foo;
同样,Base<Derived>
只是一个类。它与Derived
没有内在联系。它不是从它衍生出来的,也不是从它那里继承而已,没有。
所以,现在我们采取最后一步:
template<class T>
class Base
{
};
class Derived : public Base<Derived>
{
};
这声明了一个名为Derived
的类,它继承自名为Base<Derived>
的类。 Base<Derived>
只是一个类。这是一个非常简单的课程。不能比这更简单。它没有任何方法。它没有任何成员。也不是私人的,受保护的或公共的。它是一个小班级,但它拥有与其他班级相同的权利和特权。您可以声明指向它的指针。或者引用它。它只是一堂课。
同样,关键概念是模板的实例只是一个类。它没有继承&#34;以任何方式从参数到模板的类。在这种情况下,模板实例是完全空的,但它可以执行任何其他类可以执行的任何操作。它可以拥有公共,私人和受保护的成员。它可以从一些其他类派生,它可以是另一个模板实例(因为模板实例只是一个类)。或者,其他一些类可以从模板实例派生,因为模板实例只是一个类。
这里没有无限的筑巢。你只有一个继承自另一个类的类。第二个类恰好是一个模板实例,但我碰巧提到模板实例只是一个类吗?
答案 1 :(得分:3)
简单说明:因为以下内容完全有效:
template<class T>
class Base
{
};
class Derived /* at this point, Derived is declared (not defined) */;
int main()
{
Base<Derived> base; // the definition of Derived (or lack thereof) is irrelevant.
}