为什么不能使用 static_cast 将数组类型的纯右值转换为相同类型?

jac*_*k X 22 c++ language-lawyer c++20

#include <iostream>
int main(){
    using type = int[2];
    static_cast<type>(type{1,2});  //#1
}
Run Code Online (Sandbox Code Playgroud)

锵和GCC都抱怨#1是形成不良的,并给予怪异的诊断。

Clang 报告

static_cast from 'int *' to 'type' (aka 'int [2]') is not allowed  
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会报告

invalid 'static_cast' from type 'type' {aka 'int [2]'} to type 'type' {aka 'int [2]'}   
Run Code Online (Sandbox Code Playgroud)

但是,根据expr.static.cast#4

如果存在从 E 到 T的隐式转换序列([over.best.ics]),则表达式 E 可以显式转换为类型T

把一个类型转换成同一个类型不就叫恒等转换吗?
over.best.ics#general-8

如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由身份转换 ([over.ics.scs]) 组成的标准转换序列。

我认为这里的一个关键规则是

转换序列是 [conv] 中定义的隐式转换,这意味着它受对象的初始化规则或单个表达式([dcl.init]、[dcl.init.ref])的引用的控制。

这意味着,假设一个结果对象将由t纯右值初始化。

static_cast from 'int *' to 'type' (aka 'int [2]') is not allowed  
Run Code Online (Sandbox Code Playgroud)

#2也被 Clang 和 GCC 拒绝了。但是,这种情况应该被dcl.init.general#15.9捕获

否则,被初始化的对象的初始值是初始化表达式的(可能转换的)值。如有必要,将使用标准转换序列 ([conv]) 将初始值设定项表达式转换为目标类型的 cv 非限定版本;不考虑用户定义的转换。如果无法完成转换,则初始化格式错误。当用它不能表示的值初始化位域时,位域的结果值是实现定义的。

根据 basic.lval#1.2

纯右值是一个表达式,其求值初始化一个对象或计算一个运算符的操作数的值,如它出现的上下文所指定,或者是一个类型为 cv void 的表达式。

在这种情况下,不是类型的纯右type值不能初始化结果对象吗?

Clang 假定数组到指针的转换适用于操作数。但是,只有当项目符号进入expr.static.cast#8时才允许这种转换。换句话说,此处的转换不适用于第 4 项中的操作数。

GCC 给出了更不合理的诊断。我想知道为什么 Clang 和 GCC 禁止显式转换?

rus*_*tyx 4

原始数组很难以数组形式保存 - 在纯右值上下文中,数组会衰减为指针。

\n

但它static_cast也适用于上下文吗?规则在[expr.static.cast]中概述...

\n

我们不会转换为引用,因此我们跳过前 3 个子句并到达[expr.static.cast]/4

\n
\n

如果存在从到...的隐式转换序列 ( [over.best.ics] ),E则可以将表达式显式转换为类型。TET

\n
\n

这是行不通的,因为([conv.general]/3):

\n
\n

对于某些发明的临时变量,当且仅当声明\n格式良好时,表达式E可以隐式转换为类型T
T t=E;t

\n
\n

并且int t[2] = int[2]{1, 2};格式不正确。初始化数组的唯一合法方法在[dcl.init.general]/15.5中指定:

\n
\n

...如果目标类型是数组,则对象按如下方式初始化。令x 1 , \xe2\x80\xa6, x k为表达式列表的元素。...第 i个数组元素使用x i进行复制初始化,每个 1 \xe2\x89\xa4 i \xe2\x89\xa4 k

\n
\n

这里没有“展开”int[2]{1, 2}表达式列表中的规定。

\n
\n

否则,结果对象将直接从 初始化E

\n
\n

同样,由于格式不正确,这也不起作用int x[2](int[2]{1, 2});

\n

请注意,聚合中有一个关于数组的特殊规定,它允许轻松复制(例如std::array)。原始数组中没有这样的处理。

\n

我们跳过5。6、7 不适用。这将我们带到[expr.static.cast]/8

\n
\n

左值到右值 ([conv.lval])、数组到指针([conv.array]) 和函数到指针 ([conv.func]) 转换应用于操作数。
\n。。。

\n
\n

就是这样,强制转换无效。Clang 和 GCC 似乎都是正确的。错误报告略有不同,因为 Clang 报告衰减类型,而 GCC 报告原始类型。

\n

作为解决方法,转换为引用类型:static_cast<type&&>(type{1,2});

\n