【问题标题】:Why is this value downcast (static_cast to object type) allowed in C++20?为什么在 C++20 中允许这个值向下转换(static_cast 到对象类型)?
【发布时间】:2021-10-13 18:35:32
【问题描述】:

令我惊讶的是,gcc 11.2 accepts this code,但仅限于 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 模式下拒绝它,但即使在 C++20 模式下,clang 也会拒绝它。

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

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

【问题讨论】:

    标签: c++ language-lawyer c++20 downcast static-cast


    【解决方案1】:

    在 C++20 中是合法的。

    [expr.static.cast]/4:

    如果T 是具有第一个元素x 的聚合类型([dcl.init.aggr])并且有从Ex 类型的隐式转换序列。

    [dcl.init.aggr]/2:

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

    所以Derived 是第一个元素为Base 的聚合,并且从C++20 开始,允许从其第一个元素创建聚合。

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

    【讨论】:

    • 这是我在 C++20 中见过的最违反直觉的代码之一。聚合仍然是一个不可预测的混乱。
    • 所以我可以写int arr[2] = {1,2} ; cout &lt;&lt; (int)arr; 它会打印1?
    • @Peter-ReinstateMonica 这将打印一个指针。反过来,static_cast&lt;int[2]&gt;(42) 现在看来是合法的了。
    • @HolyBlackCat 哦。我明白了,是的。基本上,您可以将元素转换为元素的集合。在某种程度上,它们在概念上总是长度为 1 的数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 2017-01-11
    • 2014-04-04
    • 2013-07-10
    • 2020-06-24
    • 1970-01-01
    相关资源
    最近更新 更多