所以我读过这篇文章:https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
了解奇怪的重复模板模式(CRTP)是如何工作的。但它似乎取决于编译器实现,特别是编译器:
虽然我可以看到这个命令如何允许编译,但我觉得这是一个利用编译器结构而不是标准所要求的编译器通过顺序。但我觉得一组同样合法的编译器传递将是:
如果编译器使用这些传递,则在尝试评估子类型时,CRTP将在步骤2中失败。
所以我刚刚编写了这些编译器传递,但是有一个标准要求会对编译器施加约束,它会严格遵循1 st 的3次传递吗?或者CRTP是否存在于了解当前如何实现编译器的灰色区域?
正如我所看到的那样,标准需要1 st 传递来建立对象大小,然后是2 nd 传递,它编译方法。但是这个2 nd pass wold必须愿意在父对象之前构建一个子对象方法,这似乎是向后的。
答案 0 :(得分:4)
CRTP从未被实施定义或有条件支持,IIRC在发明时令人惊喜,并且从那时起就被接受了。
来自[class]
class-name 被插入到在看到 class-name 之后立即声明它的范围内。 class-name 也会插入到类本身的范围内;这被称为 inject-class-name 。
其中 class-name 是要声明的类的名称。因此, class-name 在 base-clause 之前已经可见,它是基础列表,但是只有在完全定义之后类才完成。
但是,允许模板使用不完整类型作为其类型参数,来自[temp]
模板类型参数可能是不完整的类型。
注意,即使模板类型参数不是
,模板也是完整的。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>
{
};
我们得出结论,这种模式是有效的。 编译器如何编译它是无关紧要的,如果符合标准,它将编译该代码。
答案 1 :(得分:2)
这是明确定义的。如评论中所述,即使标准也使用该功能。
考虑它的方法是,只要你编写class Child
,编译器就会认为有效地是类型的前向声明。因此,只要父类模板定义不依赖于父Child
的完整类型,它就会成功编译。 [我相信父模板类的大小不能取决于Child
的定义,但我无法向自己证明]请注意,父模板方法主体可以自由地依赖关于完整类型的子项,因为它们将是依赖类型,因此当Child
的完整定义可用时,它们的实例化被延迟到模板编译的第二阶段。
答案 2 :(得分:1)
没有。 CRTP不是特定于实现的。任何符合标准的编译器都必须支持它。
从标准的文字证明这是一项非常艰巨的任务。如果有人带着引用的回答(并在此发表评论以提醒我这样做),我会删除这个答案。
正如PasserBy所说:
严格地说,它起作用是因为注入的类名存在于 base子句
之前
base子句是冒号之后的所有内容:
class Derived : CRTP<Derived>
当François Andrieux和underscore_d指出时,我们可以间接证明该标准要求CRTP起作用,因为它定义了使用CRTP的std::enable_shared_from_this
。 (但是,它在C ++ 89中得到了很好的定义,并且在C ++ 11之前没有添加enable_shared_from_this
。)