Reputation: 29912
cppreference says:
An identifier that names a variable, a function, specialization of a concept, (since C++20) or an enumerator can be used as an expression. The result of an expression consisting of just the identifier is the entity named by the identifier. [...] The type of the expression is determined as follows:
[...] Otherwise, the type of the expression is the same as the type of the entity named.
Isn't it a bug? If the entity is a reference, like:
int &a = ...
Then a
's type as an entity is int &
, but a
's type as an expression is only int
, isn't it? An expression's type is never a reference:
[...] Each expression has some non-reference type
Bonus question: does it matter, whether a
's type (as an expression) is int
or int &
? If yes, where does it make a difference?
Note: the same wording is used at decltype:
If the argument is an unparenthesized id-expression or an unparenthesized class member access expression, then decltype yields the type of the entity named by this expression.
But clearly, decltype(a)
is int &
.
Upvotes: 2
Views: 145
Reputation: 48918
Isn't it a bug?
No. The type of a
is int
. Yeah true that this is only before the type adjustment, but since that always happens, it makes no sense to talk about expressions having reference type, since the reference disappears immediately.
does it matter, whether
a
's type (as an expression) isint
orint &
? If yes, where does it make a difference?
This is basically asking why we need value categories at all. Basically it would break move semantics because of rvalue references that are sometimes xvalues and sometimes lvalues.
Upvotes: 0
Reputation: 238281
This is what standard (draft) says:
[expr.type] Expressions / Type
If an expression initially has the type “reference to T”, the type is adjusted to T prior to any further analysis. ...
So, clearly an expression can have a reference type - initially, before adjustment for type analysis.
"Each expression has some non-reference type" is not true?
Depends on how you interpret it. An expression can have a non-reference type (initially), but all expressions have some non-reference type (after adjustment) that is used for type analysis.
[expr.prim.id.unqual] Expressions / Unqualified names
The result is the entity denoted by the identifier. ... If the entity is a template parameter object for a template parameter of type T ... [does not apply] ... Otherwise, the type of the expression is the type of the result. [Note: The type will be adjusted as described in 7.2.2 if it is cv-qualified or is a reference type. — end note] ... [Example:
void f() { float x, &r = x; [=] { decltype(x) y1; // y1 has type float decltype((x)) y2 = y1; // y2 has type float const& because this lambda // is not mutable and x is an lvalue decltype(r) r1 = y1; // r1 has type float& decltype((r)) r2 = y2; // r2 has type float const& }; }
— end example]
Decltype specifiers [dcl.type.decltype]
... if e is an unparenthesized id-expression or ..., decltype(e) is the type of the entity named by e.
Upvotes: 1