未定義の動作を叫ぶ前に、これはN4659(C ++ 17)に明示的にリストされています
i = i++ + 1; // the value of i is incremented
i = i++ + 1; // the behavior is undefined
何が変わったの?
私が収集できるものから、[N4659 basic.exec]から
特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は、シーケンスされていません。[...]演算子のオペランドの値計算は、演算子の結果の値計算の前にシーケンスされます。メモリロケーションへの副作用が同じメモリロケーションへの別の副作用または同じメモリロケーションにあるオブジェクトの値を使用した値の計算に関連してシーケンスされておらず、それらが潜在的に並行していない場合、動作は未定義です。
どこ [N4659 basic.type]で値が定義されている
自明にコピー可能な型の場合、値の表現はオブジェクト表現のビットのセットであり、 あり、実装で定義された一連の値の1つの個別の要素であるvalueます。
特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は、順序付けされていません。[...]演算子のオペランドの値計算は、演算子の結果の値計算の前にシーケンスされます。スカラーオブジェクトの副作用が、同じスカラーオブジェクトの別の副作用または同じスカラーオブジェクトの値を使用した値の計算に関連してシーケンスされていない場合、動作は未定義です。
同様に、値は [N3337 basic.type]ます
自明にコピー可能な型の場合、値の表現は、オブジェクトで表現された一連のビットであり、実装で定義された一連の値の1つの個別の要素であるvalueを決定します。
それらは重要ではない同時実行性の言及を除いて同一であり、スカラーオブジェクトの代わりにメモリロケーションを使用します。
算術型、列挙型、ポインター型、メンバー型へのポインター
std::nullptr_t
、およびこれらの型のcv修飾バージョンは、まとめてスカラー型と呼ばれます。
これは例には影響しません。
代入演算子(=)と複合代入演算子はすべて、右から左にグループ化されます。すべての左オペランドとして変更可能な左辺値が必要であり、左オペランドを参照する左辺値を返します。左のオペランドがビットフィールドの場合、すべての場合の結果はビットフィールドです。すべての場合において、割り当ては、右と左のオペランドの値計算の後、割り当て式の値計算の前にシーケンスされます。右のオペランドは左のオペランドの前に順序付けられます。
代入演算子(=)と複合代入演算子はすべて、右から左にグループ化されます。すべての左オペランドとして変更可能な左辺値が必要であり、左オペランドを参照する左辺値を返します。左のオペランドがビットフィールドの場合、すべての場合の結果はビットフィールドです。すべての場合において、割り当ては、右および左のオペランドの値計算の後、割り当て式の値計算の前にシーケンスされます。
唯一の違いは、N3337に最後の文がないことです。
左オペランドとして最後の文は、しかし、任意の重要性を持つべきではないi
でもない「別の副作用」も「同じスカラーオブジェクトの値を使用して、」とID-式は左辺値です。