3

According to [expr.ref]/(4.2) and the fact that A() is a prvalue, we conclude that A().a[0] is an xvalue. See highlighted sentence below.

If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T.

Therefore the snippet below should compile. The code doesn't compile in GCC, neither in VS2017, but it compiles in clang.

#include<iostream>
struct A
{
    int a[3];
    A(): a{1, 2, 3} {}
};

int main()
{
    int &&r = A().a[0];
    std::cout << r << '\n';
}

However, the wording in [expr.sub]/1 indicates that a[0] is an lvalue, irrespective of the value category of A(), and that seems to be incorrect to me.

A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall be a glvalue of type “array of T” or a prvalue of type “pointer to T” and the other shall be a prvalue of unscoped enumeration or integral type. The result is of type “T”. The type “T” shall be a completely-defined object type.66 The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see 8.5.2 and 8.5.6 for details of * and + and 11.3.4 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 expression E1 is sequenced before the expression E2.

Belloc
  • 6,318
  • 3
  • 22
  • 52

1 Answers1

5

There is no contradiction, you're just parsing the expression wrongly. If I understand you correctly, you're saying that E1 is A() and E2 is a[0] which is not the case.

In fact, E2 is a. Because . and [] have the same precedence, the expression is parsed as (A().a)[0].

This means that according to [expr.ref]p4.2, A().a is an xvalue (of array type), and so that per [expr.sub]p1 (A().a)[0] is thus an xvalue.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • The clang compiling it is then a bug? – Zereges Apr 25 '18 at 19:30
  • This seems to be correct. But how did you deduce, from the standard, that the operators `.` and `[]` have the same precedence? – Belloc Apr 25 '18 at 19:32
  • 2
    @Belloc You need to look at the grammar production in [expr.post](http://eel.is/c++draft/expr.post#nt:postfix-expression). It's a bit weird but class member access has the form `postfix.id` and subscript `postfix[expr-{}]`. So the only valid interpretation is that the outer expression is the `[]` one, and the inner the class member access. It wouldn't work the other way around (`a[0]` is not an id-expression). Or more informally, they are in the same paragraph :) – Rakete1111 Apr 25 '18 at 19:46
  • @Rakete1111 Unfortunately I have to disagree with you. [\[expr.ref\]\1](http://eel.is/c++draft/expr.ref#1) says clearly that `The postfix expression before the dot or arrow is evaluated;67 the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.`. So the parsing should occur according to my reasoning and therefore, [expr.ref]/(4.2) and [expr.sub]/1 are contradictory. – Belloc Apr 25 '18 at 20:19
  • @Belloc Look at the previous sentence if you don't trust the grammar :) "A postfix expression followed by a dot . or an arrow ->, optionally followed by the keyword template, and then followed by an id-expression, is a postfix expression.". `A()` is postfix, but `a[0]` is not id so the whole expression is not a postfix, it's two nested postfix expressions. – Rakete1111 Apr 25 '18 at 20:21
  • @Rakete1111 Who said `a[0]` is postfix? Is is not. Only `a`is a postfix expression. See the second definition for a [postfix-expression](http://eel.is/c++draft/expr.post#nt:postfix-expression). – Belloc Apr 25 '18 at 20:31
  • @Belloc the grammar you quoted says that. Look at the very top. But I don't really understand why you think your interpretation is right. The grammar specifies how an expression is parsed, minus any ambiguity. Any text can only confirm what the grammar already says. – Rakete1111 Apr 25 '18 at 20:41
  • @Rakete1111 You convinced me. There is no contradiction between the two statements. Thanks. – Belloc Apr 25 '18 at 22:37