У меня возникли проблемы с пониманием того, как Post Increment (++), Pre Increment работают вместе в примере

У меня возникли проблемы с пониманием того, как Post Increment (++), Pre Increment работают вместе в примере.

x++ означает добавление 1 к переменной Но меня смущает этот пример:

using namespace std;
/ run this program using the console pauser or add your own getch, system("pause") or input loop */
int main() {
    int a;
    a=8;
    cout<<++a<<a++<<endl;
    cout<<a<<endl;
    return 0;
}

Я предполагаю, что это означает, что сначала увеличивается на 1, а во втором сначала присваивается, а затем увеличивается. Это означает, что результат должен быть 9 8 и 9. Но когда я его компилирую, я получаю 10 8 и 10. Я не понимаю.


person HIFZA ZULFIQAR    schedule 09.12.2020    source источник
comment
Видите ли вы проблему с вызовом функции типа g(f(++a), a++)?   -  person Bathsheba    schedule 09.12.2020
comment
Как дважды увеличить 8 и получить 9?   -  person molbdnilo    schedule 09.12.2020
comment
если a = 8: ++a => используйте 9 и остается 9 a++ => используйте 8 и остается 9   -  person Alejandro Salamanca Mazuelo    schedule 09.12.2020
comment


Ответы (1)


Ваша путаница не имеет ничего общего с пре- и постинкрементом, а с порядком оценки operator <<. Об этом много тем, вот хорошая имхо: SO обсуждение о порядок оценки

Резюме таково:

  • До C++17 при наличии такого выражения, как std::cout << f(a) << g(a) << std::endl;, порядок вычисления (сначала f или с g) не указывается.

Это станет яснее, если мы посмотрим, что означает приведенное выше выражение. Для перегруженного operator<< фактически становится

operator<<(operator<<(std::cout, f(a)), g(a));
so: 
function  (<--------- arg 1 --------->,<arg2>)

В этом случае оценка не является последовательной, и не определено, будет ли сначала оцениваться arg1 или arg2.

  • В C++17 порядок указывается слева направо.

От [n4659] §8.2.2 : 5

Если функция оператора вызывается с использованием нотации оператора, оценка аргумента выполняется в том же порядке, что и для встроенного оператора.

Я интерпретирую это следующим образом: даже если оператор перегружен, если он вызывается как оператор (т.е. std::cout << f(a) << g(a) << std::endl;), он будет эффективно оцениваться как

std::cout.operator<<(f(a)).operator<<(g(a)).operator<<(std::endl);

Однако, если вызов сделан явно как

operator<<(operator<<(std::cout, f(a)), g(a));

это будет рассматриваться как вызов функции, и порядок по-прежнему не указан.

  • Чтобы быть в безопасности, вам лучше разделить ваши отпечатки/оценки на отдельные операторы (т. е. разделенные ;), если у вас нет веской причины не делать этого (и вы хорошо знаете детали), тем более что разные операторы ведут себя по-разному (например, + остается непоследовательным). после С++ 17).
person Cedric    schedule 09.12.2020
comment
Или, возможно, голосующий просто возражал против вашего ответа на то, что может быть 10-й версией этого вопроса за два дня. Что, на мой взгляд, не является веской причиной для понижения ответа. - person Bathsheba; 09.12.2020
comment
@Bathsheba Спасибо за отзыв! Если f и g вернут int, они будут цепочкой, а не вложенными, верно? Поскольку std::cout << f(a); == std::cout.operator(f(a));. Для пользовательских типов это будет иначе. - person Cedric; 09.12.2020
comment
Да, наверное, правда, я просто заметил, сколько других, мог бы просто удалить свой. - person Cedric; 09.12.2020
comment
@Вирсавия: Готово. Если честно, то теперь, когда я вник в это глубже, мне непонятно, почему для случая int порядок не указан. В конце концов, я ожидал, что std::cout << int(2) << int(3); будет равно std::cout.operator(int(2)).operator(int(3)); даже до C++17. Для невстроенных типов это другая история. - person Cedric; 09.12.2020