Understanding Order of Evaluation in C++ Function Calls

In C++, understanding the exact sequence in which expressions are evaluated is crucial when writing safe and predictable code. A common point of confusion arises when analyzing simple function calls like f(): Is the postfix expression f sequenced before the entire function call expression f()?

To answer this question precisely, we need to dive into the C++ Standard's definitions regarding sequenced before relationships, value computations, and expression evaluations.

Value Computation vs. Full Expression Evaluation

In C++, an expression evaluation includes both value computations (initiating computations to determine the value returned by an expression) and side effects (modifying storage, calling I/O, etc.).

According to the standard under [intro.execution]:

The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.

In the expression f(), f is the operand (the postfix expression designating the function), and () is the function call operator. Therefore, the value computation of the operand f (which yields a pointer to function / function lvalue) is strictly sequenced before the value computation of the function call expression f().

Is f Sequenced Before f() as a Whole?

Technically, in formal standard terminology, an expression evaluation consists of evaluating its subexpression operands first, then applying the operator. Since the evaluation of f is a sub-evaluation of the expression f(), asking whether f is sequenced before f() is equivalent to asking if part of an evaluation is sequenced before the whole evaluation.

The C++ standard rules clarify the relationship as follows:

  • Operand Evaluation: The evaluation of the postfix expression f and all arguments are sequenced before the actual function execution (body of f).
  • Function Body Execution: The execution of the function body is sequenced before the value computation of the result of the function call expression f().
  • Result Computation: The value computation of the call expression f() occurs after the function body finishes executing.

Thus, while the value computation of f is sequenced before the value computation of the entire call f(), the evaluation of f is part of the overall execution of the expression f().

Code Example and Standard Compliance

Consider the following simple C++ snippet:

void f() {}  int main() {     f(); } 

Under [intro.execution] p11:

// Order of execution steps for f(): // 1. Evaluate postfix expression 'f' (and any argument expressions) // 2. Sequence before precondition assertions (C++20/23 contracts, if present) // 3. Sequence before execution of every statement in the body of f // 4. Sequence before postcondition assertions // 5. Value computation of the result of f() 

Summary & Key Takeaways

  • Yes, in terms of execution order: The evaluation of the postfix expression f is completely sequenced before the function body executes and before the full result of f() is computed.
  • Formal relation: The value computation of the postfix operand f is sequenced before the value computation of the function call operator result f().
  • Practical takeaway: You can rely on the fact that function designators and argument expressions are fully evaluated before the called function begins executing.