Почему этот код не компилируется из-за ошибки:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout << ++(i++) << " " << i << endl;
return 0;
}
Пока этот код компилируется:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
cout << (++i)++ << " " << i << endl;
return 0;
}
Я не понимаю это. С моей точки зрения, было бы разумно скомпилировать первый блок. Выражение ++ (i ++) означало бы взять i, увеличить его и вывести, а затем снова увеличить.
Я не спрашиваю о неопределенном поведении в переполнении int. Во время написания вопроса я вообще не знал о значениях r и l, и мне все равно, почему ++ считается l-значением, а i ++ — нет.
Это связано с тем, что операторы post-increment и pre-increment возвращают значения разных типов. Результатом постинкремента является так называемое «значение», означающее, что его нельзя изменить. Но для предварительного увеличения необходимо изменить значение, чтобы увеличить его!
С другой стороны, результатом предварительного увеличения является lvalue, означающее, что оно может быть безопасно изменено после увеличения.
Причиной вышеупомянутых правил является тот факт, что постинкремент должен возвращать значение объекта, как это было до применения инкремента. Кстати, именно поэтому в общем случае постинкрементные значения считаются более дорогими, чем преинкрементные, когда используются на не встроенных объектах.
Короче говоря, разница в том, что в C ++ вы можете использовать любое четное количество плюсов (ограничено только пределами компилятора) для оператора приращения префикса, как это
++++++++++++++++i;
и только два плюса для постинкрементного оператора
i++;
Оператор постфиксного приращения возвращает значение (Стандарт C ++, 5.2.6 Увеличение и уменьшение)
1 Значение выражения postfix ++ является стоимость его
операнд. [Примечание: полученное значение является копией исходного значения
—Конечная записка]
В то время как префиксный оператор приращения возвращает свой операнд после приращения (Стандарт C ++, 5.3.2 Увеличение и уменьшение)
1 …Результатом является обновленный операнд; это lvalue…
В отличие от C ++ в C вы также можете применить только два плюса к объекту, используя префиксный оператор приращения. 🙂 Таким образом, компилятор C выдаст ошибку для такого выражения, как это
++++++++++++++++i;
Когда вы компилируете его с помощью clang, вы получаете сообщение об ошибке, в котором все сказано.
<source>:8:13: error: expression is not assignable
cout << ++(i++) << " " << i << endl;
Может быть, хорошо начать с оператора ++. На самом деле это сокращение для i = i + 1
, Теперь, если мы посмотрим на постфиксную версию i ++, в стандарте говорится, что она возвращает копию исходного значения и как side efect
это увеличивает первоначальное значение.
Итак, из (i ++) вы получаете rvalue и пытаетесь присвоить ему, и, как мы знаем, вы не можете назначить для rvalue.