When you initialize a reference, you bind that reference to an object, which is not necessarily the object denoted by the initializer expression.
int num1 = 10;
int num2 = 20;
int &RefOne = num1; // valid
int &RefOne = num2; // error, two definitions of RefOne
RefOne = num2; // assign num2 to num1
int &RefTwo; // error, uninitialized reference
int &RefTwo = num2; // valid
Note that the initialization of a reference is not the same as an assignment to a reference. Initialization operates on the actual reference by binding the reference to the object it is an alias for. Assignment operates through the reference on the object referred to.
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.
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.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().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.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 prvalue A().arr, and a_ref is
bound to the class prvalue A().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. 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 c to
the temporary value 1.0 that is converted from the
variable i.