在C++ 03中,表达式是rvalue或lvalue.
在C++ 11中,表达式可以是:
两类已成为五大类.
假设我有一个(普通的)类,它是可移动构造和可移动分配但不可复制构造或可复制分配:
class movable
{
public:
explicit movable(int) {}
movable(movable&&) {}
movable& operator=(movable&&) { return *this; }
movable(const movable&) = delete;
movable& operator=(const movable&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
这很好用:
movable m1(movable(17));
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为m1它不是右值:
movable m2(m1);
Run Code Online (Sandbox Code Playgroud)
但是,我可以包m1中std::move,它投射到一个右值引用,以使其工作:
movable m2(std::move(m1));
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,假设我有一个(同样微不足道的)容器类,它包含一个值:
template <typename T>
class container
{
public:
explicit container(T&& value) : value_(value) {}
private:
T value_;
};
Run Code Online (Sandbox Code Playgroud)
但是,这不起作用:
container<movable> c(movable(17));
Run Code Online (Sandbox Code Playgroud)
编译器(我试过clang 4.0和g ++ 4.7.2)抱怨我正在尝试movable在container初始化列表中使用已删除的复制构造函数.同样,包裹value在std::move使得它的工作:
explicit container(T&& value) : value_(std::move(value)) {} …Run Code Online (Sandbox Code Playgroud) 有很多与右值相关的问题,但我没有找到这些确切问题的答案。
我无法完全理解“命名引用是左值引用”的经验法则。
这看起来真的很奇怪——我们将引用声明为右值,但由于我们必须以某种方式使用这个引用(否则,有什么意义?),我们命名它,因为它被命名为它毕竟是一个左值!
考虑这段代码:
int&& foo(int&& arg)
{
arg = 10;
return arg; // ERROR, `arg` is an lvalue since it's named!
}
foo(1);
Run Code Online (Sandbox Code Playgroud)
问题是:
arg转换,然后尝试隐式转换为which 导致编译错误 - 只是相反的行为!这就是为什么我们需要它基本上是一个显式的 static_cast 到右值类型。int&&int&int&int&&std::move