**Section:** 23.7.3.3 [variant.assign] **Status:** C++17
**Submitter:** United States **Opened:** 2017-02-03 **Last modified:** 2017-07-30

**Priority: **Not Prioritized

**View all issues with** C++17 status.

**Discussion:**

The copy-assignment operator is very careful to not destroy the contained element until after a temporary has been constructed, which can be safely moved from.

This makes the `valueless_by_exception` state extremely rare, by design.

However, the same care and attention is not paid to the move-assignment operator, nor the assignment-from-deduced-value assignment template. This concern should be similarly important in these cases, especially the latter.

Proposed change: —

*[2017-03-02, Kona, Casey comments and suggests wording]*

The wording below has been developed with *much* input from Tomasz.

*[Kona 2017-03-02]*

Accepted as Immediate to resolve NB comment.

**Proposed resolution:**

This wording is relative to N4640.

Modify 23.7.3.3 [variant.assign] as indicated:

[

*Drafting note:*Presentation of para 9 immediately below has been split into individual bullets.]variant& operator=(const variant& rhs);

Let

be*j*`rhs.index()`.-1-

*Effects:*(1.1) — If neither

`*this`nor`rhs`holds a value, there is no effect. Otherwise,(1.2) — if

`*this`holds a value but`rhs`does not, destroys the value contained in`*this`and sets`*this`to not hold a value. Otherwise,(1.3) — if

`index() ==`, assigns the value contained in*j*~~rhs.index()~~`rhs`to the value contained in`*this`. Otherwise,(1.?) — if

`is_nothrow_copy_constructible_v<T`is_{j}> || !is_nothrow_move_constructible_v<T_{j}>`true`, equivalent to`emplace<`. Otherwise,*j*>(get<*j*>(rhs))(1.4) — equivalent to

`operator=(variant(rhs))`~~copies the value contained in~~.`rhs`to a temporary, then destroys any value contained in`*this`. Sets`*this`to hold the same alternative index as`rhs`and initializes the value contained in`*this`as if direct-non-list-initializing an object of type`T`with_{j}`std::forward<T`, with_{j}>(TMP)`TMP`being the temporary and`j`being`rhs.index()`

-2-

*Returns:*`*this.`-3-

*Postconditions:*`index() == rhs.index()`.-4-

*Remarks:*This function shall not participate in overload resolution unless`is_copy_constructible_v<T`is_{i}>~~&& is_move_constructible_v<T~~&& is_copy_assignable_v<T_{i}>_{i}>`true`for all.*i*~~(4.1) — If an exception is thrown during the call […]~~~~(4.2) — If an exception is thrown during the call […]~~~~(4.3) — If an exception is thrown during the call […]~~

variant& operator=(variant&& rhs) noexcept(

*see below*);Let

be*j*`rhs.index()`.-5-

*Effects:*(5.1) — If neither

`*this`nor`rhs`holds a value, there is no effect. Otherwise,(5.2) — if

`*this`holds a value but`rhs`does not, destroys the value contained in`*this`and sets`*this`to not hold a value. Otherwise,(5.3) — if

`index() ==`, assigns*j*~~rhs.index()~~`get<`to the value contained in*j*>(std::move(rhs))`*this`~~, with~~. Otherwise,being*j*`index()`(5.4) — equivalent to

`emplace<`*j*>(get<*j*>(std::move(rhs)))~~destroys any value contained in~~.`*this`. Sets`*this`to hold the same alternative index as`rhs`and initializes the value contained in`*this`as if direct-non-list-initializing an object of type`T`with_{j}`get<`with*j*>(std::move(rhs))being*j*`rhs.index()`

[…]

[…]

template <class T> variant& operator=(T&& t) noexcept(

*see below*);-8- […]

-9-

*Effects:*(9.1) — If *this holds a

`T`, assigns_{j}`std::forward<T>(t)`to the value contained in`*this`. Otherwise,(9.?) — if

`is_nothrow_constructible_v<T`is_{j}, T> || !is_nothrow_move_constructible_v<T_{j}>`true`, equivalent to`emplace<`. Otherwise,*j*>(std::forward<T>(t))(9.3) — equivalent to

`operator=(variant(std::forward<T>(t)))`~~destroys any value contained in~~.`*this`, sets`*this`to hold the alternative type`T`as selected by the imaginary function overload resolution described above, and direct-initializes the contained value as if direct-non-list-initializing it with_{j}`std::forward<T>(t)`