这个程序格式不正确:
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 { })
的子对象)可以被视为左值。
我的问题是:
答案 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 并非在所有情况下都是如此。
更新
答案 1 :(得分:3)
C ++标准草案(N4527)§5.2.1第1条规定:
表达式E1 [E2]与*((E1)+(E2))相同(根据定义)
§5.3.1第1条说:
一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是左值引用对象或表达式指向的函数。