Ответ 1
Это было бы бессмысленно. Вы изменили бы предмет в функции, и изменение было бы немедленно потеряно, потому что вещь была фактически временной.
Причина нового типа связана с необходимостью решить, что на самом деле является значением rvalue, а что нет. Только тогда вы можете использовать их для того, что они используют.
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));
}
Теперь, если у вас есть rvalue и передать его toupper, значение rvalue может быть напрямую изменено, потому что мы знаем, что временное - это отбрасывание, так что мы можем просто изменить его и не нужно копировать Это. Кроме того, одно и то же наблюдение используется для объекта, называемого move-constructors и move-assign. Правая сторона не копируется, но ее вещи просто украдены и перемещены на *this
.
Если бы вы сказали, что rvalues могут связываться с неконстантными ссылками lvalue, тогда у вас не будет возможности выяснить, ссылается ли это на значение lvalue (named object) или rvalue (временное) в конце.
Скорее всего, это немного известно, но полезно в любом случае, вы можете поместить lvalue или rvalue ref-qualifiers в функцию-член. Вот пример, который, естественно, расширяет существующую семантику ссылок rvalue на неявный параметр объекта:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
Теперь вы больше не можете сказать
string() = "hello";
Это сбивает с толку и на самом деле не имеет смысла большую часть времени. То, что делает выше &
, говорит о том, что оператор присваивания может быть вызван только на lvalues. То же самое можно сделать для rvalues, положив &&
.