【发布时间】:2013-02-04 13:05:13
【问题描述】:
给出以下 CRTP 示例:
template <typename T>
int foo(T* const)
{
return 0;
}
template <typename Derived>
struct Base
{
Base() : bar(foo(static_cast<Derived*>(this)) {};
int bar;
};
struct Derived1 : Base<Derived1> {};
this 到 Derived* 的转换在这里有效吗?我记得好像不是,但现在找不到具体的证据。
现阶段this的“自然”类型是Base* const,当然在某些情况下即使在初始化过程中静态转换this指针也是不行的,比如向上转换 em> 在基地建设完成之前 (12.7/3)。
@DeadMG 说:
标准 w.r.t 中有一个明确的例外。在初始化列表中获取它。它用于将指向您自己的指针传递给子对象。
12.6.2/12 确实说:
[ 注意:因为 mem-initializer 是在构造函数的范围内计算的,所以 this 指针可以在 mem-initializer 的表达式列表中用于引用正在初始化的对象。 ——尾注]
...虽然这不足以说明到Derived* 的转换是有效的。
我的直觉是,在对象初始化的这个阶段,this 确实 不 指向 Derived 的实例,因此,甚至只是 拥有 类型为Derived* 的指针严格来说是UB。那是因为它既不是有效指针也不是空指针。
(这可能对this 之类的方法产生实际影响,尽管在那个答案和我上面的示例中,整个事情可以通过简单地写static_cast<Derived*>(0) 来回避。)
【问题讨论】:
-
afaik 强制转换和存储结果是合法的,但在派生的 ctor 运行之前不要使用它。这方面的信息可能分散在标准中,因为我现在手头没有...
-
其实连编译都需要
static_cast<Derived* const>(this)? (编辑:nope!) -
转换是合法的,派生子对象构造前后的对象地址不会改变,所以我看不出有什么理由禁止这样做。当然,只要
foo()不取消引用指针。 -
好吧,3.8/5 似乎表明我错了。
-
@LightnessRacesinOrbit:不,静态转换只是创建一个新的指针对象,如果你想将它转换为指向指针的引用,那么你可能需要它作为 const 的引用。
标签: c++ language-lawyer