右辺値参照が右辺値にのみバインドされることになっている場合、 std::move() はどのように左辺値にバインドするのでしょうか?

DDD
リリース: 2024-11-14 10:46:01
オリジナル
969 人が閲覧しました

How does std::move() bind to lvalues when rvalue references are supposed to only bind to rvalues?

std::move の変換マジックの謎を解明する

std::move() を呼び出すと、参照されるrvalue パラメーターは lvalue にバインドできますが、通常は rvalue 参照への付加が制限されます。 std::move() の実装を詳しく調べると、この明らかな矛盾の鍵が明らかになります。

std::move() 実装の分析

洗練されたものから始めるstd::move() のバージョン:

template <typename T>
typename remove_reference<T>::type&& move(T&& arg) {
  return static_cast<typename remove_reference<T>::type&&>(arg);
}
ログイン後にコピー

ケース 1: 右辺値を使用した move() の呼び出し

次のような右辺値を指定して move() が使用される場合一時オブジェクト:

Object a = std::move(Object()); // Object() is temporary, hence prvalue
ログイン後にコピー

結果のテンプレートのインスタンス化は次のようになります:

remove_reference<Object>::type&& move(Object&& arg) {
  return static_cast<remove_reference<Object>::type&&>(arg);
}
ログイン後にコピー

remove_reference は T& を T に、または T&& を T に変換し、Object はプレーンな値であるため、最終的な関数の形態は

Object&& move(Object&& arg) {
  return static_cast<Object&&>(arg);
}
ログイン後にコピー

名前付き右辺値参照は左辺値として扱われるため、キャストは重要です。

ケース 2: 左辺値を使用した move() の呼び出し

move() が lvalues で呼び出された場合:

Object a; // a is an lvalue
Object b = std::move(a);
ログイン後にコピー

結果として move() のインスタンス化は次のようになります:

remove_reference<Object&>::type&& move(Object& && arg) {
  return static_cast<remove_reference<Object&>::type&&>(arg);
}
ログイン後にコピー

ここでも、remove_reference は Object& を ​​Object に変換し、次の結果が得られます:

Object&& move(Object& && arg) {
  return static_cast<Object&&>(arg);
}
ログイン後にコピー

参照折りたたみの本質

Object& && とその lvalue へのバインド機能を理解することが、謎を解く鍵です。 C 11 では、参照の折りたたみに関する特別なルールが導入されており、次のように規定されています。

Object & && = Object &
Object & &&& = Object &
Object && & = Object &
Object && &&& = Object &&
ログイン後にコピー

したがって、Object& && は、実際には、簡単に左辺値にバインドできる典型的な左辺値参照である Object& に変換されます。

結果の関数

これらのルールを適用すると、最終的な関数は次のようになります。

Object&& move(Object& arg) {
  return static_cast<Object&&>(arg);
}
ログイン後にコピー

右辺値のインスタンス化をミラーリングし、その引数を右辺値参照にキャストすることで、均一な動作が保証されます。 .

remove_reference の重要性

remove_reference の目的は、代替関数を調べると明らかになります。

template <typename T>
T&& wanna_be_move(T&& arg) {
  return static_cast<T&&>(arg);
}
ログイン後にコピー

左辺値でインスタンス化された場合:

Object& && wanna_be_move(Object& && arg) {
  return static_cast<Object& &&&>(arg);
}
ログイン後にコピー

参照折りたたみルールを適用すると、左辺値引数に対して左辺値を返す、使用できない移動のような関数が明らかになります。原因は、remove_reference の欠如であり、右辺値参照への適切な変換が妨げられます。

以上が右辺値参照が右辺値にのみバインドされることになっている場合、 std::move() はどのように左辺値にバインドするのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート