On 12/05/2017 08:43 PM, Alf P. Steinbach wrote:
> On 12/6/2017 1:31 AM, James R. Kuyper wrote:
>> [C++17]. 8.8p4 merely
>> implies that the evaluation of cout is sequenced before the evaluation
>> if ++i, and that the evaluation of cout << ++i is sequenced before the
>> evaluation of i++. Unless something else that's also relevant has
>> changed, that still leaves the evaluation of cout and the two
>> evaluations of i unsequenced relative to each other. In particular, the
>> evaluation of i for i++ could occur in any of three different orders
>> that are relevant:
>> 1. before the evaluation of i for ++i
>> 2. after the evaluation of i for ++i, but before the evaluation of ++i.
>> 3. after the evaluation of ++i.
>>
>> It's the fact that option 3 is permitted but not mandatory that makes
>> the behavior undefined.
>
> If I understand this right, you mean that when E1 is sequenced before E2
> in E1 << E2, only the top level operation in E1 must be done before the
> top level operation in E2, while the argument expressions to those
> operations can be evaluated in any order. Alternatively, direct object
> references can still be evaluated in any order. Or, three, …?
>
> On what is that to me arbitrary & weird interpretation based?
"Except where noted, evaluations of operands of individual operators and
of subexpressions of individual expressions are unsequenced. ... The
value computations of the operands of an operator are sequenced before
the value computation of the result of the operator." (1.9p15).
Thus, the sub-expressions of an expression are treated as separate
events that are sequenced before evaluation of the expression itself.
In every case where the standard does specify that something is
sequenced before something else, it's always the evaluation or
side-effects of the evaluation of a particular expression. It never says
that the evaluation of th expression and of all of its sub-expressions
are sequenced before the evaluation of the other expression and all of
it's sub-expressions.
This interpretation might seem weird to you, but it's pretty much the
standard interpretation I've seen used when experts discuss such issues
(non-experts use all kinds of other interpretations). I've been
participating in C and C++ newsgroups for a couple of decades now. I've
had more discussions of such issues in the context of C than in the
context of C++, but "sequenced before" was added to both standards at
about the same time with very similar wording in both standards - I
presume that the C and C++ committees deliberately worked together to
avoid having the two standards say incompatible things about such issues.
> One might argue superficially that the wording for e.g. E1 && E2 is far
> more elaborate than simply “sequenced before”, and that this could imply
> that something else is meant by “sequenced before”. But the wording for
> E1 && E2 originated with C++98, where there was no such thing as
> “sequenced before”. C++98 and C++03 instead had sequence points, which
> were not suitable for describing the evaluation of E1 && E2.
Before "sequenced before" was invented, the standard said that E1 and E2
were separated by a sequence point, and mandated that E2 must be
evaluated (if at all) after E1. The only operators that had associated
sequence points also all had wording specifying the relative order of
the things separated by those points. The current specification is an
improvement, but doesn't change what the earlier wording said (or more
precisely, failed to say) about the ordering of sub-expressions of
different expressions. The fact that A is sequenced before B, and that
the sub-expressions of A are sequenced before A, and that the
sub-expressions of B are sequenced before B, does not mean that the
sub-expressions of A are sequenced before the sub-expressions of B. That
was equally true back when those same facts were expressed using
sequence points.
>
>> If they changed << to imposes a sequence on it's operands, it's entirely
>> plausible to me that they might have changed something else that's also
>> relevant, but do you know any such change?
>
> Stefan quoted one, C++17 §
16.3.1.2/2, that when the arguments are of
> class or enumeration type, possibly with a user defined operator, the
> argument evaluation order is still as for the built-in operator.
When I said "something else", I meant something else other than the
clauses he'd already cited. Those clauses don't establish sequence
requirements sufficient to give the expression defined behavior.