почему ошибка lvalue требуется, поскольку левый операнд не отображается для строк? - PullRequest
3 голосов
/ 03 ноября 2019

В приведенном ниже фрагменте кода, почему оператор строки 2 + 3 = 5 выдает ошибку, а следующий оператор назначения конкатенации строк компилируется успешно?

#include <string>

int main() {                                                                                                                                                  
   2 + 3 = 5;   //  Error: lvalue required as left operand of assignment                                                                                                                                             
   std::string("2") + std::string("3") = std::string("5");  // Compiles successfully. why?                                                                                                 
   return 0;                                                                                                                                                 
}

Насколько я понимаю, левая часть выражения std::string("2") + std::string("3") = std::string("5") будетпроизводить временный, который составляет rvalue. Это означает, что я назначаю rvalue - точно так же, как 2 + 3 = 5. Так что это также должно выдавать ошибку lvalue required as left operand of assignment. Но это не так.

Ответы [ 2 ]

2 голосов
/ 03 ноября 2019

Объяснение

Для типов классов назначение осуществляется операторами копирования и перемещения. std::string является классом, поэтому

std::string("2") + std::string("3") = std::string("5")

является просто синтаксическим сахаром для

(std::string("2") + std::string("3")).operator=(std::string("5"))

operator= является функцией-членом. Обычно функцию-член можно вызывать как для lvalue, так и для rvalue. Следовательно, это выражение является действительным.

Стандартная ссылка

Для не перегруженных operator= (т. Е. Для int): [expr.ass] / 1

Оператор присваивания (=) и составные операторы присваивания все группы справа налево. Все требуют изменяемого lvalue в качестве своего левого операнда и возвращают lvalue, ссылаясь на левый операнд. [...]

Для перегрузки operator= (для std::string): [expr.ass] / 4

Еслилевый операнд имеет тип класса, класс должен быть завершен. Назначение объектам класса определяется оператором назначения копирования / перемещения ([class.copy], [over.ass]).

(выделено для всех)

1 голос
/ 03 ноября 2019

Это правило применяется только к объектам встроенного типа, например int.

. Это не относится к классам.

Правило, вероятно, считалось слишком ограничительным для классов, чьиоператоры могут быть перегружены для выполнения различных задач ... или, возможно, они считаются слишком ограничивающими ко времени появления C ++, но было бы неправильно нарушать старый код C, ослабляя правило и для встроенных модулей.

Несмотря на это, результатом вашего добавления на самом деле является lvalue, потому что это то, что вы получаете, когда возвращаете ссылку lvalue, такую ​​как std::string&, из функции. И это несмотря на то, что оба операнда сложения были выражениями rvalue и временными объектами. Возможно, это немного удивительно, и есть предложение сделать лучше в "распространяющейся категории значений" в таких случаях, теперь, когда язык дает нам инструменты для этого.

...