Using a temporary array as an lvalue

不羁岁月 提交于 2019-12-10 03:16:49

问题


This program is ill-formed:

struct X { int i; };

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

i, a sub-object of the temporary X { }, cannot be used as an lvalue because X { } is an rvalue.

However, this silently compiles with GCC 5.2.1 and -Wall:

using Y = int[10];

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

If the compiler is correct, then this time, the zeroth element of (Y { }), which is a subobject of (Y { }), can be treated as an lvalue.

My questions are:

  1. Is the second program ill-formed?
  2. Why (not), even though both programs seem to treat a subobject of a temporary as an lvalue?

回答1:


I believe the second case is ill-formed, if I am reading defect report 1213 correctly, it says:

Because the subscripting operation is defined as indirection through a pointer value, the result of a subscript operator applied to an xvalue array is an lvalue, not an xvalue. This could be surprising to some.

and the resolution was the following changes to the draft C++ standard section 5.2.1 [expr.sub], (bolded sections were added and strikethroughs were removed):

A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type “array of T” or “pointer to T” and the other shall have unscoped enumeration or integral type. The result is an lvalue of type “T.” The type “T” shall be a completely-defined object type.62 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [Note: see 5.3 [expr.unary] and 5.7 [expr.add] for details of * and + and 8.3.4 [dcl.array] for details of arrays. —end note], except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.

The result of Y{} is a prvalue from section 5.2.3 [expr.type.conv]:

Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4) with the specified braced-init-list, and its value is that temporary object as a prvalue.

So the result of (Y { })[0] should be an xvalue and therefore ill-formed since assignment requires a modifiable lvalue on the left operand:

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand [...]

We can find the updated wording from the defect report in the draft C++14 standard, so this change was applied after C++11 but may apply to C++11 since this was a applied via a defect report.

Why section 5.3.1 [expr.unary.op] was not also updated is unclear to me, it seems somewhat inconsistent to say the result is an lvalue which it is not in all cases.

Update

Filed a clang bug report.




回答2:


The draft of C++ standard (N4527) § 5.2.1 clause 1 says:

The expression E1[E2] is identical (by definition) to *((E1)+(E2))

§ 5.3.1 clause 1 says:

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.



来源:https://stackoverflow.com/questions/33161003/using-a-temporary-array-as-an-lvalue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!