This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2729. Missing SFINAE on `std::pair::operator=`

Section: 20.4.2 [pairs.pair], 20.5.3.2 [tuple.assign] Status: C++17 Submitter: Richard Smith Opened: 2016-06-07 Last modified: 2017-07-30

Priority: 2

View other active issues in [pairs.pair].

View all other issues in [pairs.pair].

View all issues with C++17 status.

Discussion:

`std::is_copy_assignable<std::pair<int, std::unique_ptr<int>>>::value` is `true`, and should be `false`. We're missing a "shall not participate in overload resolution unless" for `pair`'s `operator=`, and likewise for `tuple`.

[2016-08-03 Chicago LWG]

Inspired by Eric Fiselier and Ville, Walter and Nevin provide initial Proposed Resolution.

[2016-08 - Chicago]

Thurs PM: Moved to Tentatively Ready

Lots of discussion, but no one had a better idea.

Proposed resolution:

This wording is relative to N4606.

1. Change 20.4.2 [pairs.pair] as indicated:

   >     pair& operator=(const pair& p);

   > > -15- Requires Remarks: This operator shall be defined as deleted unless `is_copy_assignable_v<first_type>` is `true` and `is_copy_assignable_v<second_type>` is `true`.

   > > […]

   >     template<class U, class V> pair& operator=(const pair<U, V>& p);

   > > -18- Requires Remarks: This operator shall not participate in overload resolution unless `is_assignable_v<first_type&, const U&>` is `true` and `is_assignable_v<second_type&, const V&>` is `true`.

   > > […]

   >     pair& operator=(pair&& p) noexcept(see below);

   > > -21- Remarks: The expression inside `noexcept` is equivalent to:

   > > >     is_nothrow_move_assignable_v<T1> && is_nothrow_move_assignable_v<T2>

   > > -22- Requires Remarks: This operator shall be defined as deleted unless `is_move_assignable_v<first_type>` is `true` and `is_move_assignable_v<second_type>` is `true`.

   > > […]

   >     template<class U, class V> pair& operator=(pair<U, V>&& p);

   > > -25- Requires Remarks: This operator shall not participate in overload resolution unless `is_assignable_v<first_type&, U&&>` is `true` and `is_assignable_v<second_type&, V&&>` is `true`.

2. Change 20.5.3.2 [tuple.assign] as indicated:

   >     tuple& operator=(const tuple& u);

   > > -2- Requires Remarks: This operator shall be defined as deleted unless `is_copy_assignable_v<Ti>` is `true` for all `i`.

   > > […]

   >     tuple& operator=(tuple&& u) noexcept(see below);

   > > -5- Remark: The expression inside `noexcept` is equivalent to the logical AND of the following expressions:

   > > >     is_nothrow_move_assignable_v<Ti>

   > > where `Ti` is the `ith` type in `Types`.

   > > -6- Requires Remarks: This operator shall be defined as deleted unless `is_move_assignable_v<Ti>` is `true` for all `i`.

   > > […]

   >     template <class... UTypes>
   >       tuple& operator=(const tuple<UTypes...>& u);

   > > -9- Requires Remarks: This operator shall not participate in overload resolution unless `sizeof...(Types) == sizeof...(UTypes)` and `is_assignable_v<Ti&, const Ui&>` is `true` for all `i`.

   > > […]

   >     template <class... UTypes>
   >       tuple& operator=(tuple<UTypes...>&& u);

   > > -12- Requires Remarks: This operator shall not participate in overload resolution unless `is_assignable_v<Ti&, Ui&&> == true` for all `i`. and `sizeof...(Types) == sizeof...(UTypes)`.

   > > […]

   >     template <class U1, class U2> tuple& operator=(const pair<U1, U2>& u);

   > > -15- Requires Remarks: This operator shall not participate in overload resolution unless `sizeof...(Types) == 2`. and `is_assignable_v<T0&, const U1&>` is `true` for the first type `T0` in `Types` and `is_assignable_v<T1&, const U2&>` is `true` for the second type `T1` in `Types`.

   > > […]

   >     template <class U1, class U2> tuple& operator=(pair<U1, U2>&& u);

   > > -18- Requires Remarks: This operator shall not participate in overload resolution unless `sizeof...(Types) == 2`. and `is_assignable_v<T0&, U1&&>` is `true` for the first type `T0` in `Types` and `is_assignable_v<T1&, U2&&>` is `true` for the second type `T1` in `Types`.