使用临时数组作为左值

Using a temporary array as an lvalue

本文关键字:数组      更新时间:2023-10-16

程序格式错误:

struct X { int i; };
int main() {
    (X { }).i = 1;
}

i是临时X { }的子对象,不能用作左值,因为X { }是右值。

但是,它会在GCC 5.2.1和-Wall中静默编译:

using Y = int[10];
int main() {
    (Y { })[0] = 1;
}

如果编译器是正确的,那么这次(Y { })的第0个元素((Y { })的子对象)可以作为左值处理。

我的问题是:

  1. 第二个程序格式错误吗?
  2. 为什么(不),即使两个程序似乎都将临时对象的子对象视为左值?

我相信第二种情况是错误的,如果我正确地阅读缺陷报告1213,它说:

因为下标操作被定义为通过a的间接操作指针值,下标操作符应用于x值的结果Array是左值,而不是右值。这可能会让一些人感到惊讶。

,解决方案是对c++标准草案第5.2.1节[expr]的以下更改。Sub],(添加了粗体部分,删除了):

后缀表达式后跟方括号中的表达式是A后缀表达式。其中一种表述形式为 " T的数组"或 "指向T的指针",另一个必须是非作用域枚举类型或整型。结果是和类型的左值"t"类型"T"应该是一个完全定义的对象类型的表达式E1[E2]等于(根据定义)*((E1)+(E2))[注:参见5.3 [expr]。[1]和5.7 [expr。*和+和的详细信息添加[]8.3.4 (dcl。Array]查询阵列的详细信息。-end note],但对于数组操作数,该操作数的结果为左值

为左值,否则为xvalue。

Y{}的结果是5.2.3 [exp .type.conv]:

类似地,一个简单的类型说明符或类型名称说明符后跟一个大括号init-list创建指定类型的临时对象Direct-list-initialized(8.5.4)使用指定的大括号初始化列表,它的值是

所以(Y { })[0]的结果应该是一个x值,因此是病态的,因为赋值要求在左操作数上有一个可修改的左值:

赋值操作符(=)和复合赋值操作符都从右向左分组。都需要一个

我们可以在c++ 14标准草案的缺陷报告中找到更新的措辞,所以这个更改是在c++ 11之后应用的,但也可能适用于c++ 11,因为这是通过缺陷报告应用的。

为什么section 5.3.1 [expr.unary.]Op]也没有更新对我来说是不清楚的,说结果是左值似乎有点不一致,这不是在所有情况下。

更新

提交了clang bug报告

c++标准草案(N4527)§5.2.1条款1规定:

表达式E1[E2]与(根据定义)*((E1)+(E2))相同

§5.3.1第1条规定:

一元*操作符是间接执行的:应用该操作符的表达式必须是指向对象类型的指针,或指向函数类型的指针,且操作结果是指向该表达式所指向的对象或函数的左值