提问者:小点点

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


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

Clang和GCC都抱怨#1格式不正确,并给出了奇怪的诊断。

Clang报告

static_cast from 'int *' to 'type' (aka 'int [2]') is not allowed  

GCC报告

invalid 'static_cast' from type 'type' {aka 'int [2]'} to type 'type' {aka 'int [2]'}   

但是,根据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,它将由prvalue初始化。

type t = type{1,2};  // #2

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

否则,正在初始化的对象的初始值是初始值设定项表达式的(可能已转换的)值。如果需要,将使用标准转换序列([conv])将初始值设定项表达式转换为目标类型的cv-unqualified版本;不考虑用户定义的转换。如果不能进行转换,则表示初始化格式不正确。当用一个位字段不能表示的值初始化该位字段时,该位字段的结果值是实现定义的。

根据basic.lval#1.2

prvalue是一个表达式,其求值初始化对象或计算运算符的操作数的值(由其出现的上下文指定),或者是一个具有cv void类型的表达式。

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

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

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


共1个答案

匿名用户

原始数组很难保持数组形式--在prvalue上下文中,数组衰减为指针。

但是它是否也应用static_cast上下文?规则概述在[expr.static.cast]中...

我们没有强制转换到引用,因此我们跳过前3个子句,得到[expr.static.cast]/4:

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

这是行不通的,因为它会涉及数组到指针的衰减。

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

这将不起作用,因为无法从另一个数组直接初始化数组(int x[2](int[2]{1,2});格式不正确)。

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

对操作数应用lvalue到rvalue([conv.lval])、数组到指针([conv.array])和函数到指针([conv.func])转换。
。..

就这样,演员阵容无效。Clang和GCC似乎都是正确的。错误报告略有不同,因为Clang报告衰变的类型,而GCC报告原始类型。

作为一种解决办法,转换为引用类型:static_cast(类型{1,2});