5

Given a function call func(E1, E2, E3) where E1 etc are arbitrary expressions, is it true that each expression is indeterminately sequenced with respect to each other expression, or are all the expressions unsequenced (i.e. the evaluations can overlap)?

I've looked at the cppreference page on this and it, in rule 15, uses the sentence

In a function call, value computations and side effects of the initialization of every parameter are indeterminately sequenced with respect to value computations and side effects of any other parameter.

which I don't think is quite the same as what I'm asking as the initialisation of the parameter is just the last step in evaluation of the parameter's expression.

But rule 21 which is talking about something else seems to imply that each sub-expression in a function call is indeterminately sequenced

Every expression in a comma-separated list of expressions in a parenthesized initializer is evaluated as if for a function call (indeterminately-sequenced)

So I'm a bit confused and any guidance is appreciated.

john
  • 85,011
  • 4
  • 57
  • 81
  • 1
    I read "*order of* ***evaluation of function arguments*** *is unspecified*" to mean that the arguments are still evaluated individually i.e. "*indeterminately sequenced with respect to each other*". Whether an argument is a constant value or a complex expression should have no bearing on this. – dxiv Dec 13 '20 at 22:56
  • 1
    Read the standard, not cppreference. – n. m. could be an AI Dec 13 '20 at 23:03
  • To me an interesting question is, does it always have to fully evaluate each argument but the order in which those evaluations take place is indeterminate, or is it possible to interleave the evaluations? That is, is it possible for "start evaluating E1, switch to starting to evaluate E3, finish evaluating E1, fully evaluate E2, finish evaluating E3" to take place? – Nathan Pierson Dec 13 '20 at 23:04
  • 1
    *"as the initialisation of the parameter is just the last step in evaluation of the parameter's expression"* -- is it? Or is the evaluation of the parameter's expression the first step in initializing the parameter? – JaMiT Dec 13 '20 at 23:11
  • It used to be that the order was completly undefined... now each argument need to be evaluated **individually**. This is required to write **correct** code in some cases like initializing multiple `unique_ptr` from multiple `new` expressions *(if an exception occurs)*. On the other hand, legacy optimisations are still doable in many cases with the **AS IS** rule. – Phil1970 Dec 14 '20 at 01:40
  • @JaMiT That's precisely my confusion – john Dec 14 '20 at 07:36
  • @n.'pronouns'm. The standard is an intimidating document, it takes a while to learn how to navigate your way around it. I was somehwat familar with the C++98 version but have barely looked at any of the later versions. But in this case it seems I should have tried. – john Dec 14 '20 at 07:46
  • @NathanPierson That's my question. – john Dec 14 '20 at 07:47
  • @Phil1970 Would you have a reference for that? – dxiv Dec 14 '20 at 17:25
  • @dxiv I only remember that I have read about changes but I don't remember where or when. The sample provide in my comment was from my imagination as I don't remember the problematic case used to justify the current rules. From my understanding, with current standard, `void f(int, int); int i = 0; f(++i, ++i);` would call either `f(1, 2)` or `f(2, 1)` and `i` would be `2` at the end. At least before C++ 11, it was undefined. For third point, this is my opinion. – Phil1970 Dec 15 '20 at 01:57

1 Answers1

5

C++17 states in

8.2.2 Function call [expr.call]

4 ... The initialization and destruction of each parameter occurs within the context of the calling function.


5 ... Note: All side effects of argument evaluations are sequenced before the function is entered


5 ... The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.

I hope this (my bolding) is clear enough.

(ref: n4659, final C++17 draft)

Tony Tannous
  • 14,154
  • 10
  • 50
  • 86
  • Would be better to actually cite C++17 though – Asteroids With Wings Dec 13 '20 at 23:15
  • 1
    @AsteroidsWithWings: the actual C++ standard is paywalled, but the draft is freely available. – Violet Giraffe Dec 13 '20 at 23:16
  • 2
    @VioletGiraffe Thank you, I am aware. However, it is possible to obtain free very-close-to-publication draft versions of each standard, or some may actually pay for the standard. Regardless, the current working draft (at time of writing) is some three years newer than the standard the OP is asking about, which may well yield differences in these rules. In short: citing a C++20 draft is no proof of C++17 rules. – Asteroids With Wings Dec 13 '20 at 23:17
  • @AsteroidsWithWings same quotes in the [Final C++17 working draft](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4659.pdf) under `8.2.2 Function call` fifth paragraph. – Tony Tannous Dec 13 '20 at 23:30
  • Versions of the standard: https://stackoverflow.com/a/4653479/14065 Close to the C++17 is: [n4687](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4687.pdf) – Martin York Dec 13 '20 at 23:43
  • @MartinYork thanks, I'll bookmark this. The final working drafts can be found as well in cppreference Useful resources. https://en.cppreference.com/w/cpp/links – Tony Tannous Dec 13 '20 at 23:46
  • 1
    @TonyTannous: I would use n4687 rather than 4659 for C++17. The version after the standard is published usually is spot on to the standard and only contains minor fixes that have been discovered since publication. – Martin York Dec 13 '20 at 23:48
  • 1
    @TonyTannous Thanks, I think the phrase that removes my confusion (and was missing from cppreference) is 'including every associated value computation and side effect'. That seems to imply the whole expression is sequenced, not just the final step of initialising the parameter. – john Dec 14 '20 at 07:43
  • 1
    @MartinYork I wouldn't. n4659, as the final working draft for C++17, is not going to have such "minor fixes" that are therefore _not_ part of C++17. – Asteroids With Wings Dec 14 '20 at 12:21