Creo que esta parte del borrador del estándar con respecto al orden de evaluación es relevante:
1.9 Ejecución del programa
...
- Excepto donde se indique, las evaluaciones de operandos de operadores individuales y de subexpresiones de expresiones individuales no están secuenciadas. Los cálculos de valor de los operandos de un operador se secuencian antes del cálculo de valor del resultado del operador. Si un efecto secundario en un objeto escalar no está secuenciado en relación con otro efecto secundario en el mismo objeto escalar o un cálculo de valor utilizando el valor del mismo objeto escalar, y no son potencialmente concurrentes, el comportamiento no está definido
y también:
5.2.2 Llamada a función
...
- [Nota: Las evaluaciones de la expresión de sufijo y de los argumentos no están secuenciadas entre sí. Todos los efectos secundarios de las evaluaciones de argumentos se secuencian antes de ingresar la función - nota final]
Entonces, para su línea c.meth1(&nu).meth2(nu);, considere lo que está sucediendo en el operador en términos del operador de llamada de función para la llamada final a meth2, de modo que veamos claramente el desglose en la expresión y el argumento de sufijo nu:
operator()(c.meth1(&nu).meth2, nu);
Las evaluaciones de la expresión de sufijo y el argumento para la llamada de función final (es decir, la expresión de sufijo c.meth1(&nu).meth2y nu) no están secuenciadas entre sí según la regla de llamada de función anterior. Por lo tanto, el efecto secundario del cálculo de la expresión de sufijo en el objeto escalar no arestá secuenciado en relación con la evaluación del argumento nuantes de la meth2llamada a la función. Según la regla de ejecución del programa anterior, este es un comportamiento indefinido.
En otras palabras, no es necesario que el compilador evalúe el nuargumento de la meth2llamada después de la meth1llamada; es libre de asumir que no hay efectos secundarios que meth1afecten la nuevaluación.
El código ensamblador producido por lo anterior contiene la siguiente secuencia en la mainfunción:
- La variable
nuse asigna en la pila y se inicializa con 0.
- Un registro (
ebxen mi caso) recibe una copia del valor denu
- Las direcciones de
nuy cse cargan en registros de parámetros
meth1 se llama
- El registro del valor de retorno y el valor previamente almacenado en caché de
nuen el ebxregistro se cargan en los registros de parámetros
meth2 se llama
Críticamente, en el paso 5 anterior, el compilador permite que el valor en caché nudel paso 2 se reutilice en la llamada de función a meth2. Aquí se ignora la posibilidad de que nupueda haber sido cambiado por la llamada a meth1- 'comportamiento indefinido' en acción.
NOTA: Esta respuesta ha cambiado sustancialmente desde su forma original. Mi explicación inicial en términos de los efectos secundarios del cálculo de operandos que no se secuenciaron antes de la llamada final a la función fue incorrecta, porque lo son. El problema es el hecho de que el cálculo de los propios operandos tiene una secuencia indeterminada.