C++17 introduced rules on sequences. What was UB before is now well defined. This applies to arguments to function calls as well as a select assortment of operators:
sequenced before is an asymmetric, transitive, pair-wise relationship
between evaluations within the same thread.
- If A is sequenced before B (or, equivalently, B is sequenced after A), then evaluation of A will be complete before evaluation of B
begins.
The built-in !=
however is not sequenced (see link above). A function call would be sequenced but the order of evaluation is not guaranteed:
- 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.
(emphasis added)
To my reading, even if you wrote a wrapper function, your compiler would not be required to evaluate v
first, then std::exchange(v, pmap[v])
and finally equal(..)
. And reversing the evaluation order, I believe, would change semantics in your example.
So sadly, as nice as std::exchange
is, in this case, it is not guaranteed to do what you need it to.