はい、コードは有効であり、未定義の動作はありません。初期化子リスト内の式は、左から右に評価され、のコンストラクターの評価の前に順序付けられますS
。したがって、プログラムは常に2
variable に値を代入する必要がありますi
。
C++ 標準の§ 8.5.4 の引用:
「ブレース初期化リストの初期化リスト内では、パック展開 (14.5.3) の結果を含む初期化節は、出現順に評価されます。つまり、すべての値の計算と側面指定された初期化句に関連付けられた効果は、すべての値計算の前に順序付けられ、初期化子リストのコンマ区切りリストでそれに続くすべての初期化句に関連付けられた副作用が実行されます。」
したがって、次のようになります。
++i
評価され、生成されます (のコンストラクターのi = 1
最初の引数)。S
++i
評価され、生成されます (のコンストラクターのi = 2
2 番目の引数)。S
S
のコンストラクターが実行されます。
S
の変換演算子が実行され、 value が返されます2
。
- value
2
が割り当てられますi
(すでに value を持っていた2
)。
標準の別の関連する段落は § 1.9/15 であり、未定義の動作を持つ同様の例についても言及しています。
i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined
ただし、同じ段落には次のように書かれています。
"特に明記されている場合を除き、個々の演算子のオペランドおよび個々の式の部分式の評価は順序付けされていません。[...] 関数を呼び出すとき(関数がインラインであるかどうかにかかわらず)、引数式に関連付けられたすべての値の計算と副作用、または呼び出された関数を指定する後置式を使用して、呼び出された関数の本体内のすべての式またはステートメントの実行前にシーケンスされます。」
1) 初期化子リスト内の式の評価は左から右に配列され、2) のコンストラクターの実行はS
初期化子リスト内のすべての式の評価後に配列され、3) への代入i
は後に配列されるため、 S
(およびその変換演算子)のコンストラクターの実行、動作は明確に定義されています。