【问题标题】:why Curiously Recurring Template Pattern (CRTP) works为什么奇怪重复模板模式 (CRTP) 有效
【发布时间】:2018-04-07 15:34:57
【问题描述】:

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

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

例如,

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

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

我明白为什么以及何时可以使用它。但我想知道编译器是如何以这种方式工作的。因为在我看来,由于无休止的递归,它不应该工作:类Derived继承自Base&lt; Derived &gt;,其中Derived是继承自Base&lt; Derived &gt;的类,其中Derived...等等。

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

【问题讨论】:

    标签: c++ templates crtp


    【解决方案1】:

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

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

    对于 CRTP,这一点就在这里:

    Base<Derived>
    

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

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

    因此,只要Base 的定义不要求Derived 是完整的,一切正常。

    【讨论】:

    • @JimBalter 一个反例可能是其类型在 Derived 中定义的成员,即template &lt;class D&gt; struct B { typename D::foo member; };。如果 D 在此时不完整,则将无法实例化,因此不适合 CRTP。
    • @JimBalter 对于链表,如果编译器不允许类型在其自己的定义中命名,它必须看起来像 struct LN { int data; void *next; }; 并且你必须转换你的从外面绕过去。
    • @JimBalter 我不知道为什么你必须如此敌对,我不知道如何以另一种方式重新表述我的答案。类型可以是完整的或不完整的,CRTP 总是 接收不完整的类型作为参数,仅此而已。以完全相同的方式,您可以形成一个指向不完整类型的指针,并将其用于同一类型的定义中,这样链表就可以工作。
    【解决方案2】:

    CRTP 被命名为 recurring 因为在

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

    类模板Base在类Derived上实例化,该类继承自类Base&lt;Derived&gt;,而类模板BaseDerived上实例化,后者继承Base&lt;Dervied&gt; ... 等等。

    上面的名称Derived 用于它自己的定义中,在尚未完全定义的上下文中,因此,这使得Derived 成为一个不完整 类型。 Base&lt;Derived&gt; 正在被实例化为 Derived 类型,此时该类型不完整,因此这是递归结束的地方,因为 Base 无法知道 Derived 依次继承自 Base&lt;Derived&gt;

    【讨论】:

      【解决方案3】:
      public Base< Derived >
      

      这里,Derived 仅指在Base 中用于T 的类型名,仅此而已。您当然可以获得无限递归,但这完全取决于您如何在 Base 中使用 TT 本身只是一个与任何其他类类型一样的类型,类型本身实际上并没有做任何事情。

      【讨论】:

        猜你喜欢
        • 2019-11-18
        • 2013-02-15
        相关资源
        最近更新 更多