使用临时数组作为左值

时间:2015-10-16 01:14:24

标签: c++ c++11 language-lawyer c++14

这个程序格式不正确:

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. 为什么(不是),即使两个程序似乎都将临时的子对象视为左值?

2 个答案:

答案 0 :(得分:8)

我认为第二个案例是不正确的,如果我正确地阅读defect report 1213,它会说:

  

因为下标操作被定义为间接通过a   指针值,应用于xvalue的下标运算符的结果   array是左值,而不是xvalue。这对某些人来说可能是令人惊讶的。

并且解决方案是对C ++标准草案5.2.1 [expr.sub]草案的以下更改,(粗体部分已添加,删除删除线):

  

后缀表达式后跟方括号中的表达式是a   后缀表达。其中一个表达式应具有该类型   “T”数组或“指向T”的指针,另一个应具有无范围枚举或整数类型。结果是类型的左值   “T.”类型“T”应该是一个完全定义的对象类型.62   表达式E1 [E2]与*((E1)+(E2))相同(按照定义)[注:   有关*和+和的详细信息,请参见5.3 [expr.unary]和5.7 [expr.add]   8.3.4 [dcl.array]了解数组的详细信息。 -end note] ,除了在数组操作数的情况下,如果该操作数,结果是左值   否则是左值和x值。

Y{}的结果是5.2.3 [expr.type.conv] 部分的prvalue:

  

类似地,simple-type-specifier或typename-specifier后跟a   braced-init-list创建指定类型的临时对象   direct-list-initialized(8.5.4)与指定的braced-init-list,   它的价值是   将该临时对象作为prvalue。

所以(Y { })[0]的结果应该是一个xvalue,因此格式错误,因为赋值需要在左操作数上有一个可修改的左值:

  

赋值运算符(=)和复合赋值运算符从右到左分组。都需要一个   可修改的左值作为左操作数[...]

我们可以在draft C++14 standard中找到缺陷报告中更新的措辞,因此这个更改在C ++ 11之后应用,但可能适用于C ++ 11,因为这是通过缺陷报告应用的。< / p>

为什么部分5.3.1 [expr.unary.op] 还没有更新我不清楚,结果是 lvalue 并非在所有情况下都是如此。

更新

提交clang bug report

答案 1 :(得分:3)

C ++标准草案(N4527)§5.2.1第1条规定:

  

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

§5.3.1第1条说:

  

一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是左值引用对象或表达式指向的函数。