#include <iostream>
struct Test{
Test(int& r):rf(r){
}
int& rf;
};
int main(){
int a = 0;
Test t(a);
decltype(t.rf) b;
}
Consider the above code, the compiler complains such a code is ill-formed, because b
is of reference type and it's not be initialized. However according to the following rules, I wonder why the type of b
is a reference type?
dcl.type.simple#4
For an expression e, the type denoted by decltype(e) is defined as follows:
- if e is an unparenthesized id-expression naming a structured binding ([dcl.struct.bind]), decltype(e) is the referenced type as given in the specification of the structured binding declaration;
- otherwise, if e is an unparenthesized id-expression or an unparenthesized class member access, decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
And according to what the paragraph expr.ref#4 says:
If E2 is declared to have type “reference to T”, then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise, one of the following rules applies.
It means that the type of t.rf
is int
. I have to say it is vague that the section [expr.ref] does not say, E1.E2
is still a reference(what is the exactly entity the expression E1.E2
denotes?). It just say such an expression is lvalue
and its type is what the reference refer to.
I only find a special rule in [expr], that is:
expr#5
If an expression initially has the type “reference to T” ([dcl.ref], [dcl.init.ref]), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression. [ Note: Before the lifetime of the reference has started or after it has ended, the behavior is undefined (see [basic.life]). — end note ]
Does it mean that before analyzing the expression t.rf
, since rf
has the type “reference to T”, it should be adjusted to int
and such an expression, namely rf
designates a
to which it refers.
So, According to these above rules, the result of decltype(t.rf)
should be int
, why the compiler consider it as int&
?
if E2 is declared to have type “reference to T”, then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise, one of the following rules applies.
It means that the type of t.rf is int.
Indeed, it means that the type of the expression t.rf
is int (and category is lvalue). But the type of the named entity - which is the class member - is still lvalue reference to int and hence that is the type given by decltype(t.rf)
.
E2 is defined in the context as such:
[expr.ref]
Abbreviating postfix-expression.id-expression as E1.E2, ...
Entity is defined as:
[basic.pre]
An entity is a value, object, reference, structured binding, function, enumerator, type, class member, bit-field, template, template specialization, namespace, or pack.
The list of entities doesn't include expressions. E2 is not an entity. It is an expression that names (denotes) an entity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With