Это было бы бессмысленно. Вы бы изменили вещь в функции, и изменение сразу же было бы потеряно, потому что вещь на самом деле была временной.
Причина для нового типа связана с необходимостью решить, что на самом деле является 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 можно изменить напрямую, потому что мы знаем, что временное значение в любом случае можно выбросить, поэтому мы также можем просто изменить его и не нужно его копировать. Кроме того, то же наблюдение используется для вещей, называемых конструкторами перемещения и присваиванием перемещения. Правая часть не копируется, а ее вещи просто украдены и перемещены в *this
.
Если бы вы сказали, что rvalue могут связываться с неконстантными ссылками lvalue, то у вас не было бы возможности выяснить, ссылается ли это на lvalue (именованный объект) или rvalue (временное) в конце.
Это, вероятно, более малоизвестно, но в любом случае полезно, вы можете поместить lvalue или rvalue ref-qualifiers в функцию-член. Вот пример, который естественным образом расширяет существующую семантику ссылок rvalue на неявный объектный параметр:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
Теперь ты больше не можешь сказать
string() = "hello";
Что сбивает с толку и в большинстве случаев не имеет смысла. То, что делает &
выше, говорит о том, что оператор присваивания может быть вызван только для lvalue. То же самое можно сделать для rvalue, поставив &&
.
person
Johannes Schaub - litb
schedule
09.05.2009