(обратите внимание, что в заголовке исходного вопроса было «вместо rvalue», а не «вместо ссылки на константу». Один из приведенных ниже ответов является ответом на старый заголовок. Это было исправлено для ясности)
Одна общая конструкция в C и C++ предназначена для цепных назначений, например.
int j, k;
j = k = 1;
Второй =
выполняется первым, при этом выражение k=1
имеет побочный эффект, заключающийся в том, что k
устанавливается в 1, в то время как значение самого выражения равно 1.
Однако в C++ (но не в C) разрешена следующая конструкция, которая допустима для всех базовых типов:
int j, k=2;
(j=k) = 1;
Здесь выражение j=k
имеет побочный эффект установки j
на 2, а само выражение становится ссылкой на j
, которая затем устанавливает j
на 1. Насколько я понимаю, это потому, что выражение j=k
возвращает non em>-const
int&
, например вообще говоря, lvalue.
Это соглашение обычно также рекомендуется для определяемых пользователем типов, как описано в «Пункт 10. Операторы присваивания должны возвращать (неконстантную) ссылку на *this» в Эффективный C++ Мейерса(дополнение в скобках мое). Этот раздел книги не пытается объяснить, почему ссылка не является const
, или даже отметить неconst
ность мимоходом.
Конечно, это, безусловно, добавляет функциональности, но утверждение (j=k) = 1;
выглядит, мягко говоря, неуклюжим.
Если бы соглашение заключалось в том, чтобы встроенное присваивание возвращало ссылки const, то пользовательские классы также использовали бы это соглашение, и исходная конструкция цепочки, разрешенная в C, по-прежнему работала бы без каких-либо посторонних копий или перемещений. Например, следующее выполняется правильно:
#include <iostream>
using std::cout;
struct X{
int k;
X(int k): k(k){}
const X& operator=(const X& x){
// the first const goes against convention
k = x.k;
return *this;
}
};
int main(){
X x(1), y(2), z(3);
x = y = z;
cout << x.k << '\n'; // prints 3
}
с преимуществом в том, что все 3 (встроенные C, встроенные C++ и пользовательские типы C++) не допускают использования идиом, таких как (j=k) = 1
.
Было ли преднамеренным добавление этой идиомы между C и C++? И если да, то какая ситуация оправдывает его использование? Другими словами, какую неложную выгоду дает это расширение функциональности?
(j=k) = 1;
является следствием обобщения правил, а не преднамеренной особенностью. Я не мог себе представить, чтобы подобный код использовался каким-либо практическим образом. Может быть некоторое преимущество в том, чтоoperator=
возвращает lvalue, поскольку вы можете передать результат присваивания по ссылке в функцию, но у меня нет конкретных примеров этого навскидку. - person Silvio Mayolo   schedule 10.08.2017*
,->
,.*
или->*
), подписка, несколько результатов вызова функций, операторы-запятые, тернарные выражения и (как в этом вопросе) присваивание) являются lvalues без имен. Всегда правильное правило, которое примерно такое же простое, звучит так: «Что-то является lvalue, если вы можете взять его адрес». - person Daniel H   schedule 10.08.2017