参照を初期化するときには、その参照をオブジェクトにバインドします。 このときのオブジェクトは、必ずしも初期化指定子の式によって指定されるオブジェクトではありません。
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
参照の初期化は、参照への割り当てと同じではないことに注意してください。初期化は、実際の参照に対する別名であるオブジェクトに参照をバインドすることによって、実際の参照で動作します。割り当ては、 参照されるオブジェクトでの参照を通して動作します。
例 1
typedef int t1;
typedef const int t2;
この例では、t1 と t2 に参照関連があります。T および U に参照関連があり、T が 少なくとも U と同等の cv 修飾を持つ場合、T には U との 参照の互換性 があります。例 1 において、t1 には t2 との 参照の互換性がありませんが、t2 には t1 との参照の互換性があります。
例 2
int a = 1;
const int& ra = a;
struct A {};
struct B: A {} b;
A& rb = b;
この例において、const int 型は int 型との参照の互換性があるため、ra は直接 a にバインドできます。
構造体 A には構造体 B との参照関連があるため、rb は直接 b にバインドできます。例 3
struct A {
operator int&();
};
const int& x= A();
この例において、構造体 A はクラス型であり、const int 型には構造体 A との参照関連がありません。
しかし、A は型 int の左辺値に変換でき、const int には int との参照の互換性があります。したがって、型 const int の参照 x は A() の変換結果にバインドできます。例 4
int& a = 2; // error
const int& b = 1; // ok
この例において、変数 a は const でない左辺値参照です。コンパイラーは、右辺値の式 2 で初期化された一時変数に a をバインドすることができず、エラー・メッセージを出します。変数 b は volatile でない const の左辺値参照であり、
右辺値の式 1 で初期化される一時変数で初期化できます。例 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();
この例において、rf1、rf2、ar_ref、および a_ref はいずれも右辺値参照です。rf1 は
関数左辺値 func1 にバインドされ、rf2 は呼び出し func2() の xvalue 結果にバインドされ、ar_ref は配列 prvalue A().arr にバインドされ、a_ref はクラス prvalue A() にバインドされています。例 6
int i;
struct A {
operator int&&() {
return static_cast<int&&>(i);
}
};
const int& x = A();
int main() {
assert(&x == &i);
}
この例において、構造体 A はクラス型であり、const int 型には構造体 A との参照関連がありません。
しかし、A を型 int の xvalue に変換することができ、const int には int との参照の互換性があるため、const int の参照 x を A() で初期化し、変数 i にバインドすることができます。例 7
int i = 1;
int&& a = 2; // ok
int&& b = i; // error
double&& c = i; // ok
この例において、右辺値参照 a は右辺値式 2 で初期化される一時変数にバインドできますが、右辺値参照 b は左辺値式 i にバインドできません。右辺値参照 c は、変数 i から変換された一時値 1.0 にバインドできます。