将指向部分构造对象的指针转换为指向基类的指针是否合法?

HTN*_*TNW 6 c++ language-lawyer

也就是说,这样的事情总是合法的吗?

struct Derived;
struct Base { Base(Derived*); };
struct Derived : Base { Derived() : Base(this) { } };
Base::Base(Derived *self) {
    if(static_cast<Base*>(self) != this) std::terminate();
}

int main() {
    Derived d; // is this well-defined to never call terminate?
}
Run Code Online (Sandbox Code Playgroud)

static_cast求值时,self还没有指向一个Derived对象——那个对象正在构建中。例如,如果Derived有数据成员,它们的构造函数就不会被调用。是否仍然保证强制转换是定义的行为,从而产生一个与Base's等效的指针this(它确实指向一个完全构造的Base基类子对象)?

我认为接近回答这个问题的标准引语是[conv.ptr]/3

...转换的结果是一个指向派生类对象的基类子对象的指针。...

但我认为没有派生类对象还没有,那么会发生什么?如果它确实是未定义的,答案会改变self != static_cast<Derived*>(this)吗?

(Clang 和 GCC 编译并“按预期”运行。)

Dav*_*ing 2

这很好:[class.cdtor]/3

显式或隐式地将引用类对象的指针(泛左值)转换为指向 的直接或间接基类的X指针(引用),以及直接或间接构建其所有直接或间接基类的指针(引用)派生自应已开始,并且这些类的销毁尚未完成,否则转换会导致未定义的行为。...BXXB

它要求源类型(以及从目标类型继承的任何其他基类)已经开始其构造函数并且尚未完成其析构函数。甚至基类的初始值设定项也算作派生构造函数的开始;该标准包含一个非常相似的示例。