3

B はコンパイルできないのに、C はコンパイルできる理由を誰か説明できますか? 変数がすでに右辺値参照であるため、std::move が必要な理由がわかりません。

struct A {
  int x;
  A(int x=0) : x(x) {}
  A(A&& a) : x(a.x) { a.x = 0; }
};

struct B : public A {
  B() {}
  B(B&& b) : A(b) {}  // compile error with g++-4.7
};

struct C : public A {
  C() {}
  C(C&& c) : A(std::move(c)) {}  // ok, but why?
};
4

2 に答える 2

24

声明では:

B(B&& b)

パラメーター は、次の型で宣言されますb: rvalue への参照B

声明では:

A(b)

bは type の左辺値ですB

また、左辺値式は右辺値参照にバインドできません。具体的には、ステートメント内の右辺値参照:

A(A&& a)

このロジックは、言語の他の部分から明確に続きます。この関数を考えてみましょう:

void
f(B& b1, B b2, B&& b3)
{
   g(b1);
   g(b2);
   g(b3);
}

のパラメータfはすべて異なる型で宣言されていますが、式b1とはすべて型 の左辺値式であるためb2、がどのようにオーバーロードされても、すべて同じ関数を呼び出します。b3Bgg

C++11 では、変数の宣言と、その変数を使用した結果の式を区別することがこれまで以上に重要になっています。また、式には参照型がありません。代わりに、lvalue、xvalue、prvalue のいずれかの値カテゴリがあります。

ステートメント:

A(std::move(c))

std::move右辺値参照を返すため、問題ありません。右辺値参照を返す関数呼び出しの結果の式には、値カテゴリ xvalue があります。また、prvalues とともに、xvalues は右辺値と見なされます。そして type の右辺値式C:

std::move(c)

の右辺値参照パラメーターにバインドします: A(A&& a)

次の図 (元々は Bjarne Stroustrup によって考案されたもの) が非常に役に立ちます。

       expression
          /  \
    glvalue  rvalue
     /  \    /  \
lvalue  xvalue  prvalue
于 2012-04-19T23:24:22.080 に答える
13

&& と宣言されていても、名前付き変数は右辺値ではないためです。名前がある場合は一時的ではないため、 を使用する必要がありますstd::move

于 2012-04-19T22:53:14.427 に答える