53

I don't understand the last line of the example on page 148 of the FCD (§7.6.1.2/4):

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1 = i;     // type is const int&&
decltype(i) x2;             // type is int
decltype(a->x) x3;          // type is double
decltype((a->x)) x4 = x3;   // type is const double&

Why do the parentheses make a difference here? Shouldn't it simply be double like in the line above?

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Backreferenced: https://quuxplusone.github.io/blog/2020/01/22/expression-list-in-functional-cast/ – alfC Mar 08 '21 at 05:15

3 Answers3

42

Just above that example, it says

  • if e is an unparenthesized id-expression or a class member access (5.2.5), decltype(e) is the type of the entity named by e.
  • if e is an lvalue, decltype(e) is T&, where T is the type of e;

I think decltype(a->x) is an example of the "class member access" and decltype((a->x)) is an example of lvalue.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
20
decltype(a->x)

This gives you the type of the member variable A::x, which is double.

decltype((a->x))

This gives you the type of the expression (a->x), which is an lvalue expression (hence why it is a const reference--a is a const A*).

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 7
    Okay, I understand how the rules can be applied here now, but *why* are the rules like that? Why does it make sense to distinguish between `a->x` and `(a->x)`? It seems so random to me. Why would I ever want that behavior? Any ideas? – fredoverflow Jun 23 '10 at 09:51
  • Thanks, but both `decltype(f())` and `decltype ((f()))` yield `int` on my system. Did I misunderstand you? – fredoverflow Aug 30 '10 at 19:21
  • @Fred: Nevermind. I was wrong. In that particular case, the parentheses are ignored, so both should be `const int`. – James McNellis Aug 31 '10 at 02:17
11

The added parens are turning it into a lvalue.

MSDN says
The inner parentheses cause the statement to be evaluated as an expression instead of a member access. And because a is declared as a const pointer, the type is a reference to const double.

Greg Domjan
  • 13,943
  • 6
  • 43
  • 59