Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the compiler allowed to interlace the evaluation of subexpressions within different function arguments?

Tags:

c++

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.

like image 633
Moos Hueting Avatar asked Aug 30 '16 23:08

Moos Hueting


People also ask

What is the evaluation order of the function parameters in C++?

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.

In which order do the following will get evaluated by the C compiler?

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.

Does C++ evaluate left to right?

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.


2 Answers

In C++14 and earlier, x -> y -> a -> b is possible. The sequencing relations here are:

  • Call to x is sequenced before call to a.
  • Call to y is sequenced before call to b.
  • Call to a is sequenced before call to f.
  • Call to 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.

like image 98
M.M Avatar answered Sep 30 '22 08:09

M.M


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.

like image 33
Zenilogix Avatar answered Sep 30 '22 08:09

Zenilogix