符合标准的编译器是否可以拒绝包含非多态类型的dynamic_cast downcast的代码?

Ben*_*igt 15 c++ polymorphism virtual dynamic-cast language-lawyer

这个问题的灵感来自于此处的评论.

请考虑以下代码段:

struct X {}; // no virtual members
struct Y : X {}; // may or may not have virtual members, doesn't matter

Y* func(X* x) { return dynamic_cast<Y*>(x); }
Run Code Online (Sandbox Code Playgroud)

有几个人建议他们的编译器会拒绝它的主体func.

但是,在我看来,这是否由标准定义取决于运行时的值x.从5.2.7([expr.dynamic.cast])部分:

  1. 表达式dynamic_cast<T>(v)的结果是将表达式转换v为type 的结果T.T应该是对完整类类型的指针或引用,或者是"指向cv的 指针void".该 dynamic_cast经营者不得抛弃常量性.

  2. 如果T是指针类型,则v应该是指向完成类类型的指针的prvalue,结果是类型的prvalue T.如果T是左值引用类型,则v应该是完整类类型的左值,结果是由引用的类型的左值T.如果T是右值引用类型,则v应该是具有完整类类型的表达式,并且结果是由引用的类型的xvalue T.

  3. 如果类型v是相同的T,或者T除了类对象类型in Tcv-qualified比类对象类型更相同外,v结果是v(必要时转换).

  4. 如果值v是指针大小写中的空指针值,则结果是类型的空指针值T.

  5. 如果T是"指针CV1 B "和v具有类型"指针CV2 D ",使得B是一个基类的D,其结果是一个指针,指向唯一B的的子对象D的对象指向的v.同样,如果T是'参照CV1 B ’并且v类型为cv2 D,这 B是一个基类D,结果是 引用BD对象的唯一子对象v.结果是左值,如果T是左值引用,或者xvalue,如果T是右值引用.在指针和参考案例,如果cv2具有比cv1更大的cv资格或者如果B是不可访问或模糊的基类,则程序是不正确D.

  6. 否则,v应该是指向多态类型的左值或左值.

  7. 如果T是"指向cv的 指针void",则结果是指向由其指向的最派生对象的指针v.否则,将应用运行时检查以查看指向或引用的对象是否v可以转换为指向或引用的类型T.)指向或引用的最派生对象v可以包含其他B对象作为基类,但是这些被忽略了.

  8. 如果CT指向或引用的类类型,则运行时检查在逻辑上执行如下:

    • 如果,在指向(引用)的最多派生对象中v,v指向(引用) public对象的基类子C对象,并且只有一个对象类型C是从v结果点指向(引用)的子对象派生的(引用))到那个C对象.

    • 否则,如果vpoint(引用)到public最派生对象的基类子对象,并且最派生对象的类型具有类型的基类C,那是明确的public,并且结果指向(引用)该C 子对象的子对象.大多数派生对象.

    • 否则,运行时检查 失败.

  9. 失败的强制转换为指针类型的值是所需结果类型的空指针值.抛出失败的强制转换为引用类型std::bad_cast.

我读这个的方式,多态类型的要求仅适用于上述条件都不满足的情况,其中一个条件取决于运行时值.

当然,在少数情况下,编译器可以肯定地确定输入不能正确地为NULL(例如,当它是this指针时),但我仍然认为编译器不能拒绝代码,除非它可以确定将到达语句(通常是一个运行时问题).

警告诊断在这里当然很有价值,但它是否符合标准,编译器会拒绝此代码并出现错误?

AnT*_*AnT 3

非常好的一点。

注意在C++03中5.2.7/3和5.2.7/4的写法如下

3如果v的类型与所需的结果类型相同(为方便起见,在本描述中将其称为R ),或者它与R相同,只是 R 中的类对象类型比R中的类对象类型更具 cv 限定性v中的类对象类型,结果为v(必要时进行转换)。

4如果v的值是指针情况下的空指针值,则结果是R类型的空指针值。

对 5.2.7/3 中引入的类型的引用R似乎暗示 5.2.7/4 旨在成为 5.2.7/3 的子条款。换句话说,5.2.7/4 似乎仅适用于 5.2.7/3 中描述的条件,即类型相同时。

然而,C++11中的措辞有所不同,不再涉及R,这不再表明 5.2.7/3 和 5.2.7/4 之间有任何特殊关系。不知道是不是故意改的……