为什么在 C++20 中允许这个值向下转换(static_cast 到对象类型)?

eca*_*mur 19 c++ downcast static-cast language-lawyer c++20

令我惊讶的是,gcc 11.2接受此代码,但仅在 C++20 模式下:

struct Base {};
struct Derived : Base { int i; };
int f(Base& b) { return static_cast<Derived>(b).i; }
//                                  ^~~~~~~ oops, forgot the `&`
Run Code Online (Sandbox Code Playgroud)

同样,MSVC 19.29 在 C++20 模式下接受它,在 C++17 模式下拒绝它,但即使在 C++20 模式下,clang 也会拒绝它。

查看汇编器输出,f总是返回0,因此它忽略了Derived传递给的任何潜在的实际数据f

这是 UB,还是在 C++20 中合法,如果是,为什么?

cpp*_*ner 18

它在 C++20 中是合法的。

[expr.static.cast]/4 :

如果表达式E是具有第一个元素的聚合类型 ([dcl.init.aggr])并且存在从到 类型的隐式转换序列,则表达式可以显式转换为类型T[...] 。TxEx

[dcl.init.aggr]/2 :

聚合的元素是: [...] 对于类,按声明顺序的直接基类,后跟不是匿名联合成员的直接非静态数据成员 ([class.mem]),在声明顺序。

所以Derived是聚集,其第一个元素是Base,由于C ++ 20,它被允许创建从其第一元件的集合体。

此功能在P1975R0 “修复括号聚合初始化的措辞”中引入。

  • 这是我在 C++20 中见过的最违反直觉的代码之一。聚合仍然是一个不可预测的混乱。 (11认同)