#c
#c
Вопрос:
Есть такой код:
#include <iostream>
#include <string>
int returnnumber() { return 2; }
std::string returntext() { return "siema"; }
int main() {
std::cout << (returntext() = "cze") << std::endl; // siemacze
//std::cout << (returnnumber() = 2) << std::endl; error: lvalue required as left operand of assignment
return 0;
}
Почему можно изменить возвращаемое значение std::string , но не int ?
Ответ №1:
because std::string
— это тип класса с определенным =
оператором в качестве функции-члена.
и стандарт позволяет вызывать функции-члены для rvalues .
глупым следствием этого является то, что
struct S { int x; };
S foo() { return S(); }
int main()
{
foo() = S(); // OK, uses member assignment operator.
foo().x = 666; // !Nah, can't assign to rvalue of built-in type.
}
результаты компиляции:
Comeau C / C 4.3.10.1 (6 октября 2008 11:28:09) для ONLINE_EVALUATION_BETA2 Авторское право 1988-2008 Comeau Computing. Все права защищены. РЕЖИМ: строгие ошибки C C 0x_extensions "ComeauTest.c", строка 7: ошибка: выражение должно быть изменяемым значением lvalue foo().x = 666; // !Нет, не могу присвоить rvalue встроенного типа. ^ при компиляции "ComeauTest.c" обнаружена 1 ошибка.
однако компиляторы отличаются (или раньше отличались) в отношении того, насколько строго они применяли это тонкое правило, и применяли ли вообще.
приветствия и привет.,
Комментарии:
1. Хорошо, но для
int
оператора=
также определено.2. @anonymous downvoter: пожалуйста, объясните свой downvote, чтобы другие могли извлечь выгоду из вашего понимания или проигнорировать какую-то глупую причину.
3.@Vlad: for
int
=
— это встроеннаяoperator=
функция, в то время как forstd::string
— это функция-член. Я обновляю свой ответ, чтобы сделать это более понятным. Приветствия и привет.,4. Интересно, в чем разница: если операторам-членам разрешено применять к rvalues , почему то же самое не разрешено для встроенных операторов?
5. @Vlad: Я не знаю, но по поводу очень похожего вопроса Бьярне Страуструп (разработчик языка) ответил, что это была в основном историческая случайность. Он хотел сесть и решить проблему, но обнаружил, что у него нет времени. Есть много такого, что похоже на это… Приветствия,
Ответ №2:
Левая часть оператора присваивания для встроенного типа должна быть изменяемым значением lvalue, но возвращаемое значение функции всегда является значением rvalue, если функция не возвращает ссылочный тип.
operator =
является функцией-членом std::string
, и вы можете вызвать функцию-член для rvalue типа class .
Комментарии:
1. Вы имели в виду «левую часть оператора присваивания?»
Ответ №3:
По той же причине
std::string("siema") = "cze";
работает.
Вы создаете новый объект и применяете к operator =
нему (который std::string
имеет).
Попытка сделать это с ним не сработает, поскольку ваша функция возвращает an rvalue
. Это было бы как:
2 = 2
Вы можете поиграть с этим:
#include <iostream>
#include <string>
intamp; returnnumber() { int * k = new int; *k = 2; return *k; }
std::string returntext() { return "siema"; }
int main() {
std::cout << (returntext() = "cze") << std::endl; // siemacze
std::cout << (returnnumber() = 2) << std::endl; //no error
std::string("siema") = "cze";
return 0;
}
Но это приведет к утечке памяти, поэтому не делайте этого. Это просто доказательство концепции, что возврат an lvalue
будет работать.
Комментарии:
1. Привет, Лучиан 🙂 Также не
returntext
возвращает значение rvalue?2. Чарльз Бейли написал: но возвращаемое значение функции всегда является значением rvalue, если функция не возвращает ссылочный тип. Тогда returntext возвращает rvalue или lvalue?
3.
returntext
действительно возвращает rvalue типаstd::string
(3.10 / 5 в C 03). Для встроенных назначений требуется значение lvalue (я полагаю, это правило унаследовано от C, хотя теоретически C мог бы измениться, если бы захотел). Однако функции-члены, включая операторы, перегруженные как члены, могут вызываться для значений rvalues. Посколькуint
не имеет никаких функций-членов, тогдаstring
как имеет, эти два правила приводят к несоответствию. В C 11 существует множество других типов *value , я все еще не все понял, поэтому я не буду пытаться ссылаться на это, но эффект тот же.4. При повторном взгляде мое разъяснение было немного ленивым. Точнее сказать, что
returntext
возвращает astd::string
(и в общем случае функции возвращают либо объекты, либо ссылки), и что выражениеreturntext()
является значением rvalue (которое в данном случае ссылается на объект, возвращаемый вызовом функции). Это потому, что, если быть точным, объекты не являются значениями lvalues или rvalues, l-или-r-ness является свойством выражений.
Ответ №4:
returntext()
возвращает a std::string
, который может быть изменен на более поздних этапах, скажем, с =operator
помощью . Однако, несмотря returnnumber()
на то, что возвращает an int
, сама функция возвращает 2
значение по умолчанию a const int
и не может быть изменена, и именно поэтому компилятор жалуется.