Curiously Recurring Template Pattern 的实现是特定的吗?

Is Curiously Recurring Template Pattern Implementation Specific?

所以我读完了这个:https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

并了解 Curiously Recurring Template Pattern (CRTP) 的工作原理。但它似乎取决于编译器的实现,特别是编译器:

  1. 定义每个模板所需的 space Class
  2. 然后编译 child class 的方法
  3. 然后编译parentclass的方法

虽然我可以看到此顺序如何允许编译,但我觉得这是一种利用编译器构造而不是标准要求的编译器传递顺序。但我觉得一组同样合法的编译器传递将是:

  1. 定义 parent class
  2. 所需的 space
  3. 编译 parent classes 方法
  4. 定义 child class
  5. 所需的 space
  6. 编译 child classes 方法

如果编译器使用这些传递,CRTP 在尝试评估 child 类型时将在第 2 步失败。

所以我刚刚编写了这些编译器传递,但是是否有标准要求对编译器施加约束,使其非常遵守 1st 的 3 次传递?或者 CRTP 是否存在于了解当前编译器如何实现的灰色区域?


正如我所见,允许该标准需要一个 1st 通道来确定 object 尺寸,然后是 2 nd 编译方法的传递。但是这 2nd pass 必须愿意在 parent objects 之前构建 child objects 方法,这似乎倒退了。

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

从标准的文字中证明这一点是一项非常艰巨的任务。如果有人附带参考答案(并在此处发表评论以提醒我这样做),我将删除此答案。


正如PasserBy所说:

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

基本子句是冒号后的所有内容:

class Derived : CRTP<Derived>

As François Andrieux and underscore_d points out, we can indirectly prove that the standard requires CRTP to work, because it defines std::enable_shared_from_this 使用 CRTP。 (然而,它在 C++89 中定义良好,直到 C++11 才添加 enable_shared_from_this)。

这是明确的。如评论中所述,即使是标准也使用该功能。

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

CRTP 从来没有实现定义或有条件地支持,IIRC 它在发明时是一个惊喜,并且从那时起就被接受了。

来自[class]

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 是声明的 class 的名称。因此 class-name 已经在 base-clause 之前可见,它是碱基列表,但是 class 只有在其完整定义之后才完整。

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

A template type argument may be an incomplete type.

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

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

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

template<typename T>
struct A
{
    T t;  // ill-formed, incomplete type T in instantiation of A<B> from below
};

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

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