2 に答える
ショートストーリー
まず第一に、U
修飾付きの型の式の修飾付きのcv2
型の参照への参照バインディングの規則 L .:T
cv1
への参照
cv1 T
は、型の式で初期化できますcv2 U
参照が左辺値参照であり、初期化式である場合
- は左辺値であり、 、または
cv1 T
と参照互換性がありますcv2 U
- クラス型 [ ... ] を持っています。
それ以外の場合、
cv1
またはconst
参照が右辺値参照である必要があります。
cv1 T
がと同じ型(または の基底) であり、が等しい(またはそれより大きい)場合は、 と参照互換性があります。cv2 U
T
U
U
cv1
cv2
残念ながら (または幸運なことに?! ;)) 非定数の左辺値参照パラメーターを持つ関数は、参照互換性のない型の左辺値で呼び出すことはできません (または、渡された引数を参照互換型)。
詳細に
整数参照を受け取る関数と、定数の整数参照パラメーターを持つ 2 つ目の関数を考えてみましょう。
void doSomething (int & x)
{
// do some READ & WRITE stuff with x
x = x+5;
}
int doSomethingElse (int const & x)
{
// do some READ ONLY stuffwith x
return 3*x;
}
1 つの符号付きの値と別の符号なしの値を見てみましょう。
int a = 1;
unsigned int b = 2;
int
名前付きa
をdoSomething()
次のように渡します。
// works since x of doSomething can bind to a
doSomething(a);
// let's try to expand/"inline" what is happening
{
int & x = a;
x = 5;
}
ここには魔法はありません。参照は 5x
にバインドa
され、5 に設定されます (したがって、a も)。罰金。
b
次に、同じ関数に渡そうとします。しかし ...
// ... it doesn't work/compile since
// unsigned int is not reference compatible to int
doSomething(b); // compile error here
// what's going on here
{
int & x = b; // unsigned value cannot bind to a non-const lvalue reference!
// compile error here
x = 5;
}
ここで問題が発生し始め、doSomething
withを呼び出してb
もコンパイルされません。
const参照関数を見てみましょう。合格a
は明らかに問題ではありません。const int 参照はint
値にバインドされます。
int c = doSomethingElse(a);
// let's do some naive inlining again
int c;
{
int const & x = a;
c = 3*x;
}
まあ大丈夫そうです。c
となります3*a
。
b
その関数に渡すとどうなるでしょうか。標準では、この場合、一時的な型cv1 T
が作成され、コピー初期化規則を使用して初期化式から初期化されると記載されています。
int d = doSomethingElse(b);
// expanding this to:
int d;
{
int temp = b; // implicit conversion, not really an lvalue!
int const & x = temp;
d = 3*x;
}
swap の場合、2 番目のパラメータは int& を必要とし、署名されていない b を渡します。int& としては良くなく、ヘルプもありません。
コピーには const int& が必要です。これにより、一時的な使用が可能になります。暗黙的に int に変換できる unsigned を渡し、その一時的な int を copy に渡すことができます。
大きな違いは、2 番目のケースは 2 番目の引数を変更しないため、内部で置き換えることができることです。スワップケースで一時が許可されている場合、 a を一時的なものと交換し、 b を変更しないままにすることは、誰も望んでいないことです。