Zanim zaczniesz krzyczeć niezdefiniowane zachowanie, jest to wyraźnie wymienione w N4659 (C ++ 17)
i = i++ + 1; // the value of i is incremented
Jeszcze w N3337 (C ++ 11)
i = i++ + 1; // the behavior is undefined
Co się zmieniło?
Z tego, co mogę zebrać, z [N4659 basic.exec]
O ile nie zaznaczono inaczej, oceny operandów poszczególnych operatorów i podwyrażeń poszczególnych wyrażeń nie mają konsekwencji. [...] Obliczenia wartości operandów operatora są sekwencjonowane przed obliczeniem wartości wyniku operatora. Jeśli efekt uboczny w lokalizacji pamięci nie ma wpływu na inny efekt uboczny na tę samą lokalizację pamięci lub obliczenia wartości z wykorzystaniem wartości dowolnego obiektu w tej samej lokalizacji pamięci i nie są potencjalnie zbieżne, zachowanie jest niezdefiniowane.
Gdzie wartość jest zdefiniowana w [N4659 basic.type]
W przypadku typów, które można w prosty sposób skopiować, reprezentacja wartości jest zbiorem bitów w reprezentacji obiektu, który określa wartość , która jest jednym dyskretnym elementem zestawu wartości zdefiniowanego w implementacji
O ile nie zaznaczono inaczej, oceny operandów poszczególnych operatorów i podwyrażeń poszczególnych wyrażeń nie mają konsekwencji. [...] Obliczenia wartości operandów operatora są sekwencjonowane przed obliczeniem wartości wyniku operatora. Jeśli efekt uboczny na obiekcie skalarnym nie ma wpływu na inny efekt uboczny na ten sam obiekt skalarny lub obliczenie wartości z wykorzystaniem wartości tego samego obiektu skalarnego, zachowanie jest niezdefiniowane.
Podobnie wartość jest zdefiniowana w [N3337 basic.type]
W przypadku typów, które można w prosty sposób skopiować, reprezentacja wartości jest zbiorem bitów w reprezentacji obiektu, który określa wartość , która jest jednym dyskretnym elementem zestawu wartości zdefiniowanego w implementacji.
Są identyczne, z wyjątkiem wzmianki o współbieżności, która nie ma znaczenia, oraz przy użyciu lokalizacji pamięci zamiast obiektu skalarnego , gdzie
Typy arytmetyczne, typy wyliczeń, typy wskaźników, typy wskaźników do typów elementów
std::nullptr_t
oraz wersje tych typów kwalifikowane przez CV są wspólnie nazywane typami skalarnymi.
Co nie wpływa na przykład.
Operator przypisania (=) i operatory złożonego przypisania grupują wszystkie grupy od prawej do lewej. Wszystkie wymagają modyfikowalnej wartości jako lewego operandu i zwracają wartość odnoszącą się do lewego operandu. Wynik we wszystkich przypadkach jest polem bitowym, jeśli lewy operand jest polem bitowym. We wszystkich przypadkach przypisanie jest sekwencjonowane po obliczeniu wartości prawego i lewego operandu, a przed obliczeniem wartości wyrażenia przypisania. Prawy operand jest sekwencjonowany przed lewym operandem.
Operator przypisania (=) i operatory złożonego przypisania grupują wszystkie grupy od prawej do lewej. Wszystkie wymagają modyfikowalnej wartości jako lewego operandu i zwracają wartość odnoszącą się do lewego operandu. Wynik we wszystkich przypadkach jest polem bitowym, jeśli lewy operand jest polem bitowym. We wszystkich przypadkach przypisanie jest sekwencjonowane po obliczeniu wartości prawego i lewego operandu, a przed obliczeniem wartości wyrażenia przypisania.
Jedyną różnicą jest brak ostatniego zdania w N3337.
Ostatnie zdanie nie powinno mieć jednak żadnego znaczenia, ponieważ lewy operand i
nie jest ani „innym efektem ubocznym”, ani „wykorzystaniem wartości tego samego obiektu skalarnego”, ponieważ wyrażenie id jest wartością.
i = i++ + 1;
.