Я думаю, что эта часть проекта стандарта, касающаяся порядка оценки, актуальна:
1.9 Выполнение программы
...
- Если не указано иное, вычисления операндов отдельных операторов и подвыражений отдельных выражений неупорядочены. Вычисления значений операндов оператора последовательно выполняются перед вычислением значения результата оператора. Если побочный эффект для скалярного объекта не упорядочен относительно другого побочного эффекта для того же скалярного объекта или вычисления значения с использованием значения того же скалярного объекта, и они не являются потенциально параллельными, поведение не определено
а также:
5.2.2 Вызов функции
...
- [Примечание: все оценки постфиксного выражения и аргументов не упорядочены относительно друг друга.Все побочные эффекты оценок аргументов упорядочиваются перед вводом функции - конец примечания]
Итак, для вашей строки c.meth1(&nu).meth2(nu);
рассмотрите, что происходит в operator с точки зрения оператора вызова функции для последнего вызова meth2
, чтобы мы четко видели разбивку на постфиксное выражение и аргументnu
:
operator()(c.meth1(&nu).meth2, nu);
В оценках выражения постфикса и аргумент для вызова функции конечного (то есть выражение постфикса c.meth1(&nu).meth2
и nu
) являются unsequenced относительно друг друга в соответствии с вызовом функции правило , выше. Следовательно, побочный эффект вычисления постфиксного выражения на скалярном объекте 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
«неопределенному поведению» в действии.
ПРИМЕЧАНИЕ. Этот ответ по существу изменился по сравнению с исходной формой. Мое первоначальное объяснение с точки зрения побочных эффектов вычисления операндов, которые не были упорядочены до последнего вызова функции, было неверным, потому что они есть. Проблема заключается в том, что вычисление самих операндов имеет неопределенную последовательность.