views:

77

answers:

3

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 parenthesis make a difference here? Shouldn't it simply be double like in the line above?

+3  A: 

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
But that does not explain the const :)
FredOverflow
@FredOverflow: Does too: `a` has type `const A*`
Cubbi
How did I not see the const??? Thanks :)
FredOverflow
+3  A: 

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
+2  A: 
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
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
@James: Thanks, but both `decltype(f())` and `decltype ((f()))` yield `int` on my system. Did I misunderstand you?
FredOverflow
@Fred: Nevermind. I was wrong. In that particular case, the parentheses are ignored, so both should be `const int`.
James McNellis