A variable declared to be a T& or T&&, that is, “reference to type T” ([dcl.ref]), shall be initialized by an object, or function, of type T or by an object that can be converted into a T. [ Example:
int g(int); void f() { int i; int& r = i; r = 1; int* p = &r; int& rr = r; int (&rg)(int) = g; rg(i); int a[3]; int (&ra)[3] = a; ra[1] = i; }
— end example ]
A reference cannot be changed to refer to another object after initialization. Note that initialization of a reference is treated very differently from assignment to it. Argument passing ([expr.call]) and function value return ([stmt.return]) are initializations.
The initializer can be omitted for a reference only in a parameter declaration ([dcl.fct]), in the declaration of a function return type, in the declaration of a class member within its class definition ([class.mem]), and where the extern specifier is explicitly used. [ Example:
int& r1; extern int& r2;
— end example ]
Given types “ cv1 T1” and “ cv2 T2,” “ cv1 T1” is reference-related to “ cv2 T2” if T1 is the same type as T2, or T1 is a base class of T2. “ cv1 T1” is reference-compatible with “ cv2 T2” if T1 is reference-related to T2 and cv1 is the same cv-qualification as, or greater cv-qualification than, cv2. In all cases where the reference-related or reference-compatible relationship of two types is used to establish the validity of a reference binding, and T1 is a base class of T2, a program that necessitates such a binding is ill-formed if T1 is an inaccessible (Clause [class.access]) or ambiguous ([class.member.lookup]) base class of T2.
A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:
If the reference is an lvalue reference and the initializer expression
is an lvalue (but is not a bit-field), and “ cv1 T1” is reference-compatible with “ cv2 T2,” or
has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be converted to an lvalue of type “ cv3 T3,” where “ cv1 T1” is reference-compatible with “ cv3 T3”107 (this conversion is selected by enumerating the applicable conversion functions ([over.match.ref]) and choosing the best one through overload resolution ([over.match])),
then the reference is bound to the initializer expression lvalue in the first case and to the lvalue result of the conversion in the second case (or, in either case, to the appropriate base class subobject of the object). [ Note: The usual lvalue-to-rvalue ([conv.lval]), array-to-pointer ([conv.array]), and function-to-pointer ([conv.func]) standard conversions are not needed, and therefore are suppressed, when such direct bindings to lvalues are done. — end note ]
[ Example:
double d = 2.0; double& rd = d; const double& rcd = d; struct A { }; struct B : A { operator int&(); } b; A& ra = b; const A& rca = b; int& ir = B();
— end example ]
Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference. [ Example:
double& rd2 = 2.0; int i = 2; double& rd3 = i;
— end example ]
If the initializer expression
is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or
has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be converted to an xvalue, class prvalue, or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3” (see [over.match.ref]),
then the reference is bound to the value of the initializer expression in the first case and to the result of the conversion in the second case (or, in either case, to an appropriate base class subobject). In the second case, if the reference is an rvalue reference and the second standard conversion sequence of the user-defined conversion sequence includes an lvalue-to-rvalue conversion, the program is ill-formed.
[ Example:
struct A { }; struct B : A { } b; extern B f(); const A& rca2 = f(); A&& rra = f(); struct X { operator B(); operator int&(); } x; const A& r = x; int i2 = 42; int&& rri = static_cast<int&&>(i2); B&& rrb = x; int&& rri2 = X();
— end example ]
Otherwise:
If T1 is a class type, user-defined conversions are considered using the rules for copy-initialization of an object of type “ cv1 T1” by user-defined conversion ([dcl.init], [over.match.copy]); the program is ill-formed if the corresponding non-reference copy-initialization would be ill-formed. The result of the call to the conversion function, as described for the non-reference copy-initialization, is then used to direct-initialize the reference. The program is ill-formed if the direct-initialization does not result in a direct binding or if it involves a user-defined conversion.
If T1 is a non-class type, a temporary of type “ cv1 T1” is created and copy-initialized ([dcl.init]) from the initializer expression. The reference is then bound to the temporary.
If T1 is reference-related to T2:
cv1 shall be the same cv-qualification as, or greater cv-qualification than, cv2; and
if the reference is an rvalue reference, the initializer expression shall not be an lvalue.
[ Example:
struct Banana { }; struct Enigma { operator const Banana(); }; void enigmatic() { typedef const Banana ConstBanana; Banana &&banana1 = ConstBanana(); Banana &&banana2 = Enigma(); } const double& rcd2 = 2; double&& rrd = 2; const volatile int cvi = 1; const int& r2 = cvi; double d2 = 1.0; double&& rrd2 = d2; int i3 = 2; double&& rrd3 = i3;
— end example ]
In all cases except the last (i.e., creating and initializing a temporary from the initializer expression), the reference is said to bind directly to the initializer expression.
[ Note: [class.temporary] describes the lifetime of temporaries bound to references. — end note ]
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4