右值是你从表达式中得到的(从 C 标准中得到的有用的简化,但在 C++ 标准中没有用词)。左值是“定位器值”。左值可以用作右值。引用总是左值,即使是 const。
您必须注意的主要区别可以浓缩为一项:您不能获取右值的地址(同样,不是标准的,而是对规则的有用概括)。或者换一种说法,你不能为右值确定一个精确的位置——如果你可以的话,那么你就会有一个左值。 (但是,您可以将 const& 绑定到右值以“将其固定到位”,而 0x 正在彻底改变规则。)
不过,用户定义类型 (UDT) 有点特殊:如果类的接口允许,您可以将任何右值转换为左值:
struct Special {
Special& get_lvalue() { return *this; }
};
void f() {
// remember "Special()" is an rvalue
Special* p = &Special().get_lvalue(); // even though you can't dereference the
// pointer (because the object is destroyed), you still just took the address
// of a temporary
// note that the get_lvalue() method doesn't need to operate on a const
// object (though that would be fine too, if the return type matched)
}
您的A() = a 正在发生类似的事情,除了通过编译器提供的赋值运算符将右值A() 转换为*this。引用标准,12.8/10:
如果类定义没有显式声明复制赋值运算符,则隐式声明。类 X 的隐式声明的复制赋值运算符将具有以下形式
X& X::operator=(const X&)
然后它会继续进行更多的资格和规格,但这是重要的一点。由于这是一个成员函数,它可以在右值上调用,就像 Special::get_lvalue 一样,就好像你写了A().operator=(a) 而不是A() = a。
int() = 1 正如您所发现的那样被明确禁止,因为 int 没有 operator= 以相同的方式实现。但是,类型之间的这种细微差异在实践中并不重要(至少不是我发现的那样)。
POD 表示普通旧数据,是使用 memcpy 指定的要求的集合,相当于复制。非 POD 是您无法使用 memcpy 复制的任何类型(与 POD 天然相反,这里没有隐藏任何内容),这往往是您将用 C++ 编写的大多数类型。成为 POD 或非 POD 并不会改变上述任何一项,并且确实是一个单独的问题。