C++ Expression Sequencing: Is Postfix 'f' Sequenced Before Function Call 'f()'?
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
fand all arguments are sequenced before the actual function execution (body off). - 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
fis completely sequenced before the function body executes and before the full result off()is computed. - Formal relation: The value computation of the postfix operand
fis sequenced before the value computation of the function call operator resultf(). - Practical takeaway: You can rely on the fact that function designators and argument expressions are fully evaluated before the called function begins executing.