关于c ++:奇怪的重复模板模式实现特定?

Is Curiously Recurring Template Pattern Implementation Specific?

所以我读过这个:https://en.wikipedia.org/wiki/cur奇地重复使用模板模式

并了解奇怪的循环模板模式(CRTP)是如何工作的。但似乎这取决于编译器的实现,特别是编译器:

  • 定义每个模板类所需的空间
  • 然后编译子类的方法
  • 然后编译父类的方法
  • 虽然我可以看到这个顺序如何允许编译,但我觉得它是一个利用编译器构造的过程,而不是标准所要求的编译器传递顺序。但我觉得一套同样合法的编译器传递应该是:

  • 定义父类所需的空间
  • 编译父类方法
  • 定义子类所需的空间
  • 编译子类方法
  • 如果编译器使用这些过程,那么当CRTP试图计算子类型时,它将在步骤2失败。

    所以我刚刚编写了这些编译器过程,但是有没有一个标准要求对编译器施加约束,使其在很大程度上遵循第一个过程的3个过程?或者,CRTP是否存在于一个灰色地带,知道编译器目前是如何实现的?

    正如我所看到的那样,标准需要第一次通过建立对象大小,然后第二次通过编译方法。但是这第二遍wld必须愿意在父对象之前构建子对象方法,这看起来是向后的。


    CRTP从未被定义或有条件地支持实现,IIRC在发明时是一个令人愉快的惊喜,从此被接受。

    来自[阶级]

    A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.

    其中,class name是要声明的类的名称。因此,类名称在BASE子句(即基列表)之前已经可见,但类只有在其完整定义之后才完整。

    但是,允许模板使用不完整的类型作为其类型参数,来自[temp]

    A template type argument may be an incomplete type.

    注意,模板是完整的,即使它的类型参数不是。

    1
    2
    3
    4
    5
    6
    7
    8
    template<typename>
    struct S {};

    struct U     // U is visible after this line
        : S<U>   // S<U> is a complete type
    {
        S<U> s;  // well-formed
    };           // U is complete after this line

    实例化模板可以完成的原因是模板类型参数本身在模板中可能不完整,从而避免了循环逻辑

    1
    2
    3
    4
    5
    6
    7
    8
    9
    template<typename T>
    struct A
    {
        T t;  // ill-formed, incomplete type T in instantiation of A from below
    };

    struct B : A  // implicit instantiation of the specialization A
    {
    };

    我们认为这种模式是有效的。编译器如何编译它是无关紧要的,如果它符合标准,它将编译该代码。


    这是很明确的。正如注释中所指出的,即使是标准也会使用功能。

    考虑它的方法是,只要编写class Child,编译器就会认为该类型的正向声明是有效的。只要父类模板定义不依赖于Child的完整类型,它将成功编译父类。[我认为父模板类的大小不能依赖于Child的定义,但我不能自己证明这一点]请注意,父模板方法体可以自由地依赖子对象的完整类型,因为它们将是依赖类型,因此它们的实例化被延迟到模板编译的第二阶段。当Child的完整定义可用时。


    不,CRTP不是特定于实现的。它必须由任何符合标准的编译器支持。

    用标准的话来证明这一点是一项相当艰巨的任务。如果有人带着参考答案来找我,我会删除这个答案(并在这里做评论以提醒我这样做)。

    如过路人所说:

    Strictly speaking, it works because the injected class name exists before the base clause

    BASE子句是冒号后面的所有内容:

    1
    class Derived : CRTP<Derived>

    作为弗兰?ois andrieux和underlined指出,我们可以间接证明标准要求CRTP工作,因为它定义了使用CRTP的std::enable_shared_from_this。(然而,它在C++ 89中被很好地定义,并且EDCOX1,1)不被添加直到C++ 11)。