Reference binding
Suppose T and U are two types. If ignoring top-level cv-qualifiers, T is of the same type as U or is a base class of U, T and U are reference-related.
Example 1
typedef int t1;
typedef const int t2;
In this example, t1 and t2 are reference-related.
If T and U are reference-related, and T is at least as cv-qualified as U, T is reference-compatible with U. In Example 1, t1 is not reference-compatible with t2, but t2 is reference-compatible with t1.
If an lvalue reference r to type T is to be initialized by an expression e of type U, and T is reference-compatible with U, the reference r can be bound directly to e or a base class subobject of e unless T is an inaccessible or ambiguous base class of U.
Example 2
int a = 1;
const int& ra = a;
struct A {};
struct B: A {} b;
A& rb = b;
In this example, the const int type is reference-compatible with the int type, so ra can be bound directly to a. Structure A is reference-related to structure B, so rb can be bound directly to b.
If an lvalue reference r to type T is to be initialized by an expression e of type U, r can be bound to the lvalue result of the conversion of e or a base class of e if the following conditions are satisfied. In this case, the conversion function is chosen by overload resolution.
- U is a class type.
- T is not reference-related to U.
- e can be converted to an lvalue of type S, and T is reference-compatible with S.
Example 3
struct A {
operator int&();
};
const int& x= A();
In this example, structure A is a class type, and the const int type is not reference-related to structure A. However, A can be converted to an lvalue of type int, and const int is reference-compatible with int, so reference x of type const int can be bound to the conversion result of A().
By default, the compiler cannot bind a non-const or volatile lvalue reference to an rvalue.
Example 4
int& a = 2; // error
const int& b = 1; // ok
In this example, the variable a is a non-const lvalue reference. The compiler cannot bind a to the temporary initialized with the rvalue expression 2, and issues an error message. The variable b is a non-volatile const lvalue reference, which can be initialized with the temporary initialized with the rvalue expression 1.
Beginning of C++11 only.
Suppose an expression e of type U belongs to one of the following value categories:
- An xvalue
- A class prvalue
- An array prvalue
- A function lvalue
If an rvalue reference or a non-volatile const lvalue reference r to type T is to be initialized by the expression e, and T is reference-compatible with U, reference r can be initialized by expression e and bound directly toe or a base class subobject of e unless T is an inaccessible or ambiguous base class of U.
Example 5
int& func1();
int& (&&rf1)()=func1;
int&& func2();
int&& rf2 = func2();
struct A{
int arr[5];
};
int(&&ar_ref)[5] = A().arr;
A&& a_ref = A();
In this example, rf1, rf2, ar_ref, and a_ref are all rvalue references. rf1 is bound to the function lvalue func1, rf2 is bound to the xvalue result of the call func2(), ar_ref is bound to the array prvalueA().arr, and a_ref is bound to the class prvalue A().
Suppose r is an rvalue reference or non-volatile const lvalue reference to type T, and r is to be initialized by an expression e of type U. r can be bound to the conversion result of e or a base class of e if the following conditions are satisfied. In this case, the conversion function is chosen by overload resolution.
- U is a class type.
- T is not reference-related to U.
- e can be converted to an xvalue, class prvalue, or function lvalue type of S, and T is reference-compatible with S.
Example 6
int i;
struct A {
operator int&&() {
return static_cast<int&&>(i);
}
};
const int& x = A();
int main() {
assert(&x == &i);
}
In this example, structure A is a class type, and the const int type is not reference-related to structure A. However, A can be converted to an xvalue of type int, and const int is reference-compatible with int, so reference x of const int can be initialized with A() and bound to variable i.
An rvalue reference can be initialized with an lvalue in the following contexts:
- A function lvalue
- A temporary converted from an lvalue
- An rvalue result of a conversion function for an lvalue object that is of a class type
Example 7
int i = 1;
int&& a = 2; // ok
int&& b = i; // error
double&& c = i; // ok
In this example, the rvalue reference a can be bound to the temporary initialized with the rvalue expression 2, but the rvalue reference b cannot be bound to the lvalue expression i. You can bind the rvalue reference cto the temporary value 1.0 that is converted from the variable i.
End of C++11 only.