14

私が(些細な)クラスを持っているとしましょう。これは、移動構築可能で移動割り当て可能ですが、コピー構築可能またはコピー割り当て可能ではありません。

class movable
{
  public:
    explicit movable(int) {}
    movable(movable&&) {}
    movable& operator=(movable&&) { return *this; }
    movable(const movable&) = delete;
    movable& operator=(const movable&) = delete;
};

これは正常に機能します。

movable m1(movable(17));

もちろん、これはm1右辺値ではないため、機能しません。

movable m2(m1);

しかし、それを右辺値参照にキャストするでラップm1して、それを機能させることができます:std::move

movable m2(std::move(m1));

ここまでは順調ですね。ここで、単一の値を保持する(同様に些細な)コンテナクラスがあるとします。

template <typename T>
class container
{
  public:
    explicit container(T&& value) : value_(value) {}
  private:
    T value_;
};

ただし、これは機能しません。

container<movable> c(movable(17));

コンパイラ(私はclang4.0とg++ 4.7.2を試しました)は、の初期化リストmovableでの削除されたコピーコンストラクタを使用しようとしていると文句を言いcontainerます。繰り返しますが、ラップvalueインstd::moveすると機能します。

    explicit container(T&& value) : value_(std::move(value)) {}

しかし、なぜstd::moveこの場合に必要なのですか?valueまだタイプではありませんmovable&&か?とどうvalue_(value)違うのmovable m1(movable(42))

4

2 に答える 2

16

これvalueは、 が名前付き変数であり、左辺値であるためです。は、ムーブ コンストラクターのオーバーロードが一致std::moveするように、右辺値にキャストし直す必要があります。T

別の言い方をすると、右辺値参照は右辺値にバインドできますが、それ自体は右辺値ではありません。これは単なる参照であり、式では左辺値です。そこから右辺値である式を作成する唯一の方法は、キャストすることです。

于 2012-10-30T12:43:20.957 に答える
5

とどうvalue_(value)違うのmovable m1(movable(42))

名前付きの右辺値参照は左辺値 (したがって、削除されたコピー ctor にバインドされます) ですが、一時的なものは右辺値 (具体的には prvalue) です。

§5 [expr] p6

[...] 一般に、このルールの効果は、名前付きの右辺値参照が左辺値として扱われ、オブジェクトへの名前のない右辺値参照が xvalue として扱われることです [...]

同様に例から:

A&& ar = static_cast<A&&>(a);

arは左辺値です。

上記の引用は非規範的な注記からのものですが、第 5 節の残りの部分でxvalueのみを作成する式を説明しているため、適切な説明です†</sup> (別名、指定された式のみが xvalue を作成し、それ以外の式は作成しません)。完全なリストについては、こちらも参照してください。

† xvalues は rvalues の 1 つのサブグループであり、prvalues はもう 1 つのサブグループです。説明については、この質問を参照してください。

于 2012-10-30T12:47:01.650 に答える