Перш ніж почати кричати невизначену поведінку, це чітко вказано в N4659 (C ++ 17)
i = i++ + 1; // the value of i is incremented
Ще в N3337 (C ++ 11)
i = i++ + 1; // the behavior is undefined
Що змінилося?
З того, що я можу зібрати, з [N4659 basic.exec]
За винятком випадків, в яких оцінюються операнди окремих операторів і субекспресії окремих виразів не є наслідком. [...] Обчислення значень операндів оператора секвенуються перед обчисленням значення результату оператора. Якщо побічний ефект на розташування пам'яті не є наслідком щодо іншого побічного ефекту на те саме місце пам'яті або обчислення значення, використовуючи значення будь-якого об'єкта в тому самому місці пам'яті, і вони потенційно не є одночасним, поведінка не визначена.
Де значення визначено в [N4659 basic.type]
Для тривіально копіюваних типів представлення значення - це набір бітів в представленні об'єкта, що визначає значення , яке є одним дискретним елементом визначеного реалізацією набору значень
За винятком випадків, в яких оцінюються операнди окремих операторів і субекспресії окремих виразів не є наслідком. [...] Обчислення значень операндів оператора секвенуються перед обчисленням значення результату оператора. Якщо побічний ефект на скалярний об’єкт не є наслідком щодо іншого побічного ефекту на той самий скалярний об'єкт або обчислення значення, використовуючи значення того ж скалярного об'єкта, поведінка не визначена.
Так само значення визначається в [N3337 basic.type]
Для тривіально копіюваних типів представлення значення - це набір бітів у представленні об'єкта, що визначає значення , яке є одним дискретним елементом визначеного реалізацією набору значень.
Вони ідентичні, за винятком згадки про одночасність, яка не має значення, і з використанням місця пам'яті замість скалярного об'єкта , де
Арифметичні типи, типи перерахування, типи вказівників, вказівники на типи членів
std::nullptr_t
та версії цих типів, кваліфіковані cv, називаються спільно скалярними типами.
Що не впливає на приклад.
Від [N4659 expr.ass]
Оператор присвоєння (=) і оператори присвоєння складної групи всі групи справа наліво. Усі вимагають модифікованого lvalue як їх лівого операнда і повертають значення lvalue, що посилається на лівий операнд. Результатом у всіх випадках є бітове поле, якщо лівий операнд є бітовим полем. У всіх випадках призначення присвоюється послідовно після обчислення значення правого і лівого операндів і перед обчисленням значення виразу призначення. Правий операнд секвенується перед лівим операндом.
Від [N3337 expr.ass]
Оператор присвоєння (=) і оператори присвоєння складної групи всі групи справа наліво. Усі вимагають модифікованого lvalue як їх лівого операнда і повертають значення lvalue, що посилається на лівий операнд. Результатом у всіх випадках є бітове поле, якщо лівий операнд є бітовим полем. У всіх випадках призначення присвоюється послідовно після обчислення значення правого і лівого операндів і перед обчисленням значення виразу призначення.
Єдина відмінність - останнє речення, яке відсутнє в N3337.
Останнє речення, однак, не повинно мати жодного значення, оскільки лівий операнд i
не є ні "іншим побічним ефектом", ні "використанням значення того ж скалярного об'єкта", оскільки вираз id є значенням.
i = i++ + 1;
.