評価の順序に関する標準草案のこの部分は関連があると思います:
1.9プログラムの実行
...
- 特に明記されていない限り、個々の演算子のオペランドおよび個々の式の部分式の評価は、シーケンスされていません。演算子のオペランドの値計算は、演算子の結果の値計算の前にシーケンスされます。スカラーオブジェクトの副作用が同じスカラーオブジェクトの別の副作用または同じスカラーオブジェクトの値を使用した値の計算に関連してシーケンスされておらず、それらが潜在的に同時に発生しない場合、動作は未定義です。
そしてまた:
5.2.2関数呼び出し
...
- [注:後置式と引数の評価は、すべて相互に順序付けされていません。引数評価のすべての副作用は、関数に入る前に順序付けされます—終わりの注意]
したがって、あなたの行c.meth1(&nu).meth2(nu);
では、への最後の呼び出しの関数呼び出し演算子に関してoperatorで何が起こっているかを考えてくださいmeth2
。そうすれば、後置式と引数の内訳が明確にわかりますnu
。
operator()(c.meth1(&nu).meth2, nu);
最後の関数呼び出しの後置式と引数の評価(つまり、後置式c.meth1(&nu).meth2
とnu
)は、上記の関数呼び出し規則に従って、相互に順序付けられていません。したがって、スカラーオブジェクトに対する後置式の計算の副作用は、関数呼び出しの前の引数評価に比べて順序付けされていません。上記のプログラム実行ルールでは、これは未定義の動作です。ar
nu
meth2
言い換えれば、コンパイラーが呼び出しの後に呼び出しのnu
引数を評価する必要はありません- 評価に影響を与える副作用がないと仮定することは自由です。meth2
meth1
meth1
nu
上記で生成されたアセンブリコードには、main
関数に次のシーケンスが含まれています。
- 変数
nu
はスタックに割り当てられ、0で初期化されます。
- レジスター(
ebx
私の場合)は、値のコピーを受け取りますnu
- のアドレス
nu
とc
パラメータレジスタへのロード
meth1
呼ばれる
- 戻り値レジスタと、以前にキャッシュされた値の
nu
中ebx
レジスタは、パラメータ・レジスタにロードされています
meth2
呼ばれる
重要なのは、上記のステップ5で、コンパイラーがnu
ステップ2のキャッシュ値をへの関数呼び出しで再利用できるようにすることmeth2
です。ここでは、動作中の「未定義の動作」のnu
呼び出しによって変更された可能性を無視meth1
します。
注:この回答は、元の形式から実質的に変更されています。最後の関数呼び出しの前にシーケンスされていないオペランド計算の副作用に関する私の最初の説明は正しくありませんでした。問題は、オペランド自体の計算が不確定に順序付けられるという事実です。