I am wondering about the following situation:
void f(int a, int b) { }
int a(int x) { std::cout << "func a" << std::endl; return 1; }
int b(int x) { std::cout << "func b" << std::endl; return 2; }
int x() { std::cout << "func x" << std::endl; return 3; }
int y() { std::cout << "func y" << std::endl; return 4; }
f(a(x()), b(y()));
After reading http://en.cppreference.com/w/cpp/language/eval_order I am still having difficulty to understand whether the following evaluation order is possible:
x()
-> y()
-> a()
-> b()
or that the standard guarantees that a(x())
and b(y())
will be evaluated as units, so to speak.
In other words, is there any possibility this will print
func x
func y
func a
func b
Running this test on GCC 5.4.0 gives the to my mind more logical
func y
func b
func x
func a
but this of course does not tell me anything about what the standard requires. It would be nice to get a reference to the standard.
The order of evaluation of function arguments is unspecified. Consequently, parameters of a function shall not be used in a default argument, even if they are not evaluated. The same verbiage is used by C++14 standard as well, and is found under the same section.
The compiler will evaluate them in any order. It may choose another order when the same expression is evaluated again, but this will not affect the evaluated answer.
With C++17 the order of evaluation of the last code snippet is right to left; therefore, the expression has well-defined behaviour. Here are the additional guarantees we have with C++17: Postfix expressions are evaluated from left to right. This includes functions calls and member selection expressions.
In C++14 and earlier, x -> y -> a -> b
is possible. The sequencing relations here are:
x
is sequenced before call to a
.y
is sequenced before call to b
.a
is sequenced before call to f
.b
is sequenced before call to f
.There are no other restrictions on the order. If you want to enforce some particular ordering then you'll have to break this call up into multiple full-expressions.
In the C++14 standard this intent is clarified by the note [expr.call]/8:
[Note: The evaluations of the postfix expression and of the arguments are all unsequenced relative to one another. All side effects of argument evaluations are sequenced before the function is entered. —end note ]
As noted in comments, the cppreference page lists some more sequencing rules marked as "since C++17". This is based on n4606, the latest published draft for C++17. So it is possible that for C++17, this order will no longer be allowed.
Another way to look at it:
There would be no benefit to evaluating both x and y before commencing evaluation of either a or b. In fact, there would be a penalty. An extra intermediate result would have to be temporarily held somewhere which would either require an additional stack push/pop, or consume an additional CPU register (overuse of which would lead to additional stack operations anyway). While it may be of little or no consequence for the example you provided, more complex cases would reveal the inefficiencies.
The rule could be viewed as laziest possible evaluation i.e. not performing evaluations until needed so as to avoid carrying extra temporary results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With