2012-04-19 100 views
2

有人可以解释为什么B不编译,但C呢?我不明白为什么std :: move是必需的,因为变量已经是右值ref。rvalue refs和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? 
}; 
+0

接受一个答案! – Walter 2012-11-30 14:25:30

回答

12

因为命名变量不是右值,宣布& &时也是如此。如果它有一个名称,那么它不是暂时的,因此您需要使用std::move

21

在声明中:

B(B&& b) 

参数b声明与类型:右值引用B

在语句:

A(b) 

表达bB类型的左值。

而左值表达式不能结合rvalue引用:特别是在语句中的右值参考:

A(A&& a) 

此逻辑干净地从语言的其他部分如下。考虑一下这个功能:

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

即使的f参数都声明与不同类型的表达式b1b2b3B类型的所有左值表达式,从而将所有调用同一个函数g,无重要的是如何g过载。

在C++ 11中,区分变量的声明和使用该变量的表达式比以往任何时候都更加重要。表达式从来没有引用类型。相反,它们有一个值为的值类别,其正是以下值之一:左值,左值,右值。

声明:

A(std::move(c)) 

是确定的,因为std::move返回一个右值引用。函数调用返回右值引用的表达式具有值类别:xvalue。与prvalues一起,xvalues被视为rvalues。和C类型的右值表达式:

std::move(c) 

将结合在右值参考参数:A(A&& a)

我发现下面的图(最初由Bjarne Stroustrup的发明)非常有帮助:

 expression 
     /\ 
    glvalue rvalue 
    /\ /\ 
lvalue xvalue prvalue 
+0

感谢您的详细解答。显然这里有很多细微的东西需要理解。 – drwowe 2012-04-23 15:16:06