A& & -> A&
参照の折りたたみ規則 ( C++98/03 である を保存) が存在する理由の 1 つは、完全な転送を機能させるためです。
「完全な」転送とは、ユーザーが関数を直接呼び出したかのように効果的にパラメーターを転送することを意味します (転送によって壊れる省略を除く)。ユーザーが渡すことができる値には、左辺値、xvalue、および prvalues の 3 種類があり、受け取る場所が値を受け取る方法は 3 つあります。参照。
この関数を考えてみましょう:
template<class T>
void Fwd(T &&v) { Call(std::forward<T>(v)); }
値による
パラメータを値で受け取る場合Call
は、そのパラメータにコピー/移動する必要があります。どちらが受信値であるかによって異なります。入力値が左辺値の場合、左辺値をコピーする必要があります。入力値が右辺値 (まとめて xvalues と prvalues) である場合、そこから移動する必要があります。
左辺値で呼び出す場合Fwd
、C++ の型推定規則は、 が左辺値の型であると推定されることを意味しT
ます。明らかに、左辺値が の場合、と推定されます。参照折りたたみルールは、for 、左辺値参照になることを意味します。これはまさに と呼ぶ必要があるものです。左辺値参照で呼び出すと、直接呼び出した場合とまったく同じように、コピーが強制されます。Type&
Type
const
const Type&
Type & &&
Type &
v
Call
Fwd
右辺値 (つまり、Type
一時的な式または特定のType&&
式) で呼び出す場合、T
は として推定されType
ます。参照の折りたたみ規則によりType &&
、移動/コピーが引き起こされます。これは、直接呼び出した場合とほとんど同じです (除外を除く)。
左辺値参照による
左辺値参照によって値を取得する場合Call
、ユーザーが左辺値パラメーターを使用する場合にのみ呼び出すことができます。それが const-lvalue 参照である場合は、何でも (lvalue、xvalue、prvalue) から呼び出すことができます。
Fwd
左辺値で呼び出すと、再びType&
の型として取得されv
ます。これは非 const 左辺値参照にバインドします。これを const 左辺値で呼び出すと、 が得られますconst Type&
。これは、 の const 左辺値参照引数にのみバインドされCall
ます。
Fwd
xvalue で呼び出すと、再びType&&
の型として取得されv
ます。xvalueは非 const 左辺値参照にバインドできないため、非 const 左辺値を取る関数を呼び出すことはできません。これは const 左辺値参照にバインドできるため、 a をCall
使用すると、xvalue でconst&
呼び出すことができます。Fwd
Fwd
prvalue を指定して呼び出すと、再び が返さType&&
れるため、すべてが以前と同じように機能します。const 以外の左辺値を取る関数にテンポラリを渡すことはできないため、転送しようとすると、同様に転送関数が停止します。
右辺値参照による
右辺値参照によって値を取得する場合Call
、ユーザーが xvalue または右辺値パラメーターを使用する場合にのみ呼び出し可能にする必要があります。
Fwd
左辺値で呼び出すと、 が得られType&
ます。これは右辺値参照パラメーターにバインドされないため、コンパイル エラーが発生します。Aconst Type&
も右辺値参照パラメーターにバインドしないため、引き続き失敗します。Call
これは、左辺値で直接呼び出した場合にまさに起こることです。
Fwd
xvalue で呼び出すと、 が得られますがType&&
、これは機能します (cv-qualification はもちろん重要です)。
prvalue を使用する場合も同様です。
std::フォワード
std::forward 自体も同様の方法で参照折りたたみ規則を使用して、着信右辺値参照を xvalue (xvalue である関数の戻り値Type&&
) として渡し、着信左辺値参照を左辺値 ( を返すType&
) として渡します。