令我惊讶的是,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 `&`
同样,MSVC 19.29在c++ 20模式下接受它,在c++ 17模式下拒绝它,但是clang即使在c++ 20模式下也拒绝它。
查看汇编器输出,f
总是返回0
,因此它忽略了传递给f
的任何潜在Derived
的实际数据。
这是UB,或者在c++ 20中是合法的,如果是,为什么?
在c++ 20中是合法的。
[expr.static.cast]/4:
表达式
E
可以显式转换为类型T
[…]如果T
是一个聚合类型([dcl.init.aggr]),其第一个元素为x
,并且存在从E
到x
类型的隐式转换序列。
[dcl.init.aggr]/2:
聚合的元素是:[…]对于一个类,直接的基类按声明顺序排列,然后是直接的非静态数据成员([class.mem]),它们不是匿名联合的成员,按声明顺序排列。
所以Derived
是一个第一个元素是Base
的聚合,从c++ 20开始,允许从它的第一个元素创建一个聚合。
此特性在P1975R0"修正括号聚合初始化"的措辞"中引入。