57

次のリンクは、参照の折りたたみの 4 つの形式を提供します (これらが 4 つの形式のみであることが正しい場合): http://thbecker.net/articles/rvalue_references/section_08.html

リンクから:

  1. A& & が A& になる
  2. A& && は A& になります
  3. A&& & が A& になる
  4. A&& && は A&& になります

経験に基づいた推測を行うことはできますが、これらの参照崩壊規則のそれぞれの背後にある理論的根拠について簡潔な説明が必要です。

関連する質問: これらの参照折りたたみルールは、C++ 11std::move()で、 、などの STL ユーティリティによって内部的にstd::forward()使用されていますか? (注: C++03 以前ではなく、C++11 で参照折りたたみ規則が使用されているかどうかを具体的に尋ねています。)

などの C++11 ユーティリティを認識しているため、この関連する質問をしますが、参照折りたたみ規則の必要性を回避するために C++11 で日常的に使用されているstd::remove_reference参照関連ユーティリティ、またはそれらが参照崩壊規則と組み合わせて使用​​されているかどうか。std::remove_reference

4

2 に答える 2

41

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&Typeconstconst Type&Type & &&Type &vCall

Fwd右辺値 (つまり、Type一時的な式または特定のType&&式) で呼び出す場合、Tは として推定されTypeます。参照の折りたたみ規則によりType &&、移動/コピーが引き起こされます。これは、直接呼び出した場合とほとんど同じです (除外を除く)。

左辺値参照による

左辺値参照によって値を取得する場合Call、ユーザーが左辺値パラメーターを使用する場合にのみ呼び出すことができます。それが const-lvalue 参照である場合は、何でも (lvalue、xvalue、prvalue) から呼び出すことができます。

Fwd左辺値で呼び出すと、再びType&の型として取得されvます。これは非 const 左辺値参照にバインドします。これを const 左辺値で呼び出すと、 が得られますconst Type&。これは、 の const 左辺値参照引数にのみバインドされCallます。

Fwdxvalue で呼び出すと、再びType&&の型として取得されvます。xvalueは非 const 左辺値参照にバインドできないため、非 const 左辺値を取る関数を呼び出すことはできません。これは const 左辺値参照にバインドできるため、 a をCall使用すると、xvalue でconst&呼び出すことができます。Fwd

Fwdprvalue を指定して呼び出すと、再び が返さType&&れるため、すべてが以前と同じように機能します。const 以外の左辺値を取る関数にテンポラリを渡すことはできないため、転送しようとすると、同様に転送関数が停止します。

右辺値参照による

右辺値参照によって値を取得する場合Call、ユーザーが xvalue または右辺値パラメーターを使用する場合にのみ呼び出し可能にする必要があります。

Fwd左辺値で呼び出すと、 が得られType&ます。これは右辺値参照パラメーターにバインドされないため、コンパイル エラーが発生します。Aconst Type&も右辺値参照パラメーターにバインドしないため、引き続き失敗します。Callこれは、左辺値で直接呼び出した場合にまさに起こることです。

Fwdxvalue で呼び出すと、 が得られますがType&&、これは機能します (cv-qualification はもちろん重要です)。

prvalue を使用する場合も同様です。

std::フォワード

std::forward 自体も同様の方法で参照折りたたみ規則を使用して、着信右辺値参照を xvalue (xvalue である関数の戻り値Type&&) として渡し、着信左辺値参照を左辺値 ( を返すType&) として渡します。

于 2012-12-05T15:34:06.480 に答える
6

ルールは実際には非常に簡単です。Rvalue referenceは、それを使用する式を超えて保持されない一時的な値へのlvalue reference参照です。永続的なデータを参照するのとは対照的です。したがって、永続データへの参照がある場合、それを他のどの参照と組み合わせても、実際に参照されるデータは左辺値です。これは最初の 3 つのルールをカバーしています。4 番目の規則も自然です。右辺値参照への右辺値参照は、依然として非永続データへの参照であるため、右辺値参照が生成されます。

はい、C++11 ユーティリティはこれらのルールに依存しています。リンクによって提供される実装は、実際のヘッダーと一致します: http://en.cppreference.com/w/cpp/utility/forward

そして、はい、リンクで説明されているように、std::moveおよびユーティリティを使用すると、テンプレート引数控除規則とともに折りたたみ規則が適用されます。std::forward

isなどの型特性の使用法はremove_reference、ニーズによって異なります。最もカジュアルなケースmoveをカバーします。forward

于 2012-12-05T15:31:06.783 に答える