这将毫无意义。您将更改函数中的事物,并且更改将立即丢失,因为该事物实际上是临时的。
新类型的原因源于需要能够决定什么实际上是右值,什么不是。只有这样你才能真正将它们用于它们所使用的很酷的东西。
string toupper(string && s) { // for nonconst rvalues
for(char &c : s) make_uppercase(c);
return move(s); // move s into a returned string object
}
string toupper(string const& s) { // for the rest
// calls the rvalue reference version, by passing
// an rvalue copy.
return toupper(string(s));
}
现在,如果您有一些右值并将其传递给 toupper,则可以直接修改右值,因为我们知道临时的东西无论如何都是一次性的,所以我们也可以直接更改它而不需要复制它。同样,同样的观察也用于移动构造函数和移动赋值。右手边没有被复制,只是它的东西被偷走并移到了*this
.
如果您说右值可以绑定到非 const 左值引用,那么您将无法确定最终是引用左值(命名对象)还是右值(临时)。
它可能鲜为人知,但无论如何有用,您可以将左值或右值引用限定符放在成员函数上。这是一个示例,它自然地将右值引用的现有语义扩展到隐式对象参数:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
现在,你不能再说
string() = "hello";
这是令人困惑的,并且在大多数情况下并没有真正的意义。上面所做的&
就是说赋值运算符只能在左值上调用。右值也可以这样做,方法是把&&
.