Penso che questa parte della bozza di standard riguardante l'ordine di valutazione sia rilevante:
1.9 Esecuzione del programma
...
- Tranne dove indicato, le valutazioni degli operandi dei singoli operatori e delle sottoespressioni delle singole espressioni non sono sequenziali. I calcoli del valore degli operandi di un operatore vengono sequenziati prima del calcolo del valore del risultato dell'operatore. Se un effetto collaterale su un oggetto scalare non viene sequenziato rispetto a un altro effetto collaterale sullo stesso oggetto scalare o un calcolo del valore utilizzando il valore dello stesso oggetto scalare e non sono potenzialmente concorrenti, il comportamento non è definito
e anche:
5.2.2 Chiamata di funzione
...
- [Nota: le valutazioni dell'espressione postfissa e degli argomenti sono tutte senza sequenze l'una rispetto all'altra. Tutti gli effetti collaterali delle valutazioni degli argomenti vengono sequenziati prima di inserire la funzione - nota finale]
Quindi per la tua linea c.meth1(&nu).meth2(nu);
, considera cosa sta succedendo in operator in termini di operatore di chiamata di funzione per la chiamata finale a meth2
, in modo da vedere chiaramente la scomposizione nell'espressione e nell'argomento postfisso nu
:
operator()(c.meth1(&nu).meth2, nu);
Le valutazioni dell'espressione postfissa e dell'argomento per la chiamata di funzione finale (cioè l'espressione postfissa c.meth1(&nu).meth2
e nu
) non sono sequenziali l'una rispetto all'altra secondo la regola della chiamata di funzione sopra. Pertanto, l' effetto collaterale del calcolo dell'espressione postfissa sull'oggetto scalare non ar
è sottoposto a sequenze rispetto alla valutazione dell'argomento nu
prima della meth2
chiamata alla funzione. In base alla regola di esecuzione del programma sopra, questo è un comportamento non definito.
In altre parole, non è necessario che il compilatore valuti l' nu
argomento della meth2
chiamata dopo la meth1
chiamata: è libero di assumere alcun effetto collaterale di meth1
influenzare ilnu
valutazione.
Il codice assembly prodotto da quanto sopra contiene la seguente sequenza nella main
funzione:
- Variabile
nu
viene allocata nello stack e inizializzata con 0.
- Un registro (
ebx
nel mio caso) riceve una copia del valore dinu
- Gli indirizzi di
nu
ec
vengono caricati nei registri dei parametri
meth1
è chiamato
- Il registro del valore restituito e il valore precedentemente memorizzato nella cache di
nu
inebx
registro vengono caricati nei registri di parametro
meth2
è chiamato
Fondamentalmente, nel passaggio 5 sopra il compilatore consente nu
di riutilizzare il valore memorizzato nella cache del passaggio 2 nella chiamata di funzione a meth2
. Qui si ignora la possibilità che nu
potrebbe essere stata modificata dalla chiamata ameth1
"comportamento indefinito" in azione.
NOTA: questa risposta è cambiata nella sostanza rispetto alla sua forma originale. La mia spiegazione iniziale in termini di effetti collaterali del calcolo dell'operando non sequenziato prima della chiamata finale della funzione non era corretta, perché lo sono. Il problema è il fatto che il calcolo degli operandi stessi è in sequenza indeterminata.