Evaluation order with std::tie() and assignment

Viewed 94

Is the following valid?

template <typename T>
std::pair<T, T> foo(T one, T two) { ... }

std::tie(one, two) = foo(std::move(one), std::move(two));

(Assuming that the classes involved handle assigning to a moved-from object in a valid manner).


From reading the updated evaluation order proposal, my assumption was that this was fixed, but I can't find an exact reference in the standard that verifies this. Could someone help provide that?

2 Answers

The relevant section from the standard can be found in [expr.ass]/1 and it has

In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression. The right operand is sequenced before the left operand. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation.

So, according to this, foo(std::move(one), std::move(two)); will be evaluated first, leaving one and two as moved from objects once std::tie(one, two) is evaluated. tie create references, so there is no accessing the moved from objects there. Then the assignment actually happens meaning one and two get assigned to via std::tuple::operator = and get whatever value foo returns. This is legal and well defined.

The code is valid, regardless of C++17 changes to evaluation order of =.

Since LHS doesn't read from one, two, but merely takes their addresses, it being unsequenced (pre-C++17) relative to the RHS doesn't cause UB.

Related