Title
swappable traits for variants
Status
c++17
Section
[variant.swap][variant.specalg]
Submitter
Agustín K-ballo Bergé

Created on 2016-07-19.00:00:00 last changed 89 months ago

Messages

Date: 2016-09-12.04:46:33

Proposed resolution:

This wording is relative to N4606.

  1. Modify [variant.swap] as indicated:

    void swap(variant& rhs) noexcept(see below);
    

    -?- Requires: Lvalues of type Ti shall be swappable and is_move_constructible_v<Ti> shall be true for all i.

    […]

    -2- Throws: If index() == rhs.index(), aAny exception thrown by swap(get<i>(*this), get<i>(rhs)) with i being index() and variant's move constructor and assignment operator. Otherwise, any exception thrown by the move constructor of Ti or Tj with i being index() and j being rhs.index().

    -3- Remarks: This function shall not participate in overload resolution unless is_swappable_v<Ti> is true for all i. If an exception is thrown during the call to function swap(get<i>(*this), get<i>(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues of Ti with i being index(). If an exception is thrown during the exchange of the values of *this and rhs, the states of the values of *this and of rhs are determined by the exception safety guarantee of variant's move constructor and move assignment operator. The expression inside noexcept is equivalent to the logical AND of is_nothrow_move_constructible_v<Ti> && is_nothrow_swappable_v<Ti> for all i.

  2. Modify [variant.specalg] as indicated:

    template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);
    

    -1- Effects: Equivalent to v.swap(w).

    -2- Remarks: This function shall not participate in overload resolution unless is_move_constructible_v<Ti> && is_swappable_v<Ti> is true for all i. The expression inside noexcept is equivalent to noexcept(v.swap(w)).

Date: 2016-09-09.00:00:00

[ 2016-09-09 Issues Resolution Telecon ]

Move to Tentatively Ready

Date: 2016-08-15.00:00:00

[ 2016-08-13, Reopened by Casey Carter ]

It is possible to exchange the value of two variants using only move construction on the alternative types, as if by

auto tmp = move(x);
x.emplace<i>(move(y));
y.emplace<j>(move(tmp));
where i is y.index() and j is tmp.index(). Consequently, variant's member swap need not require move assignable alternatives.

Date: 2016-08-13.12:44:23

[ 2016-07 Chicago ]

Monday: P1 - review later in the week

Fri PM: Move to Tentatively Ready

Previous resolution [SUPERSEDED]:

This wording is relative to N4606.

  1. Modify [variant.swap] as indicated:

    void swap(variant& rhs) noexcept(see below);
    

    -?- Requires: Lvalues of type Ti shall be swappable and is_move_constructible_v<Ti> && is_move_assignable_v<Ti> is true for all i.

    […]

    -3- Remarks: This function shall not participate in overload resolution unless is_swappable_v<Ti> is true for all i. If an exception is thrown during the call to function swap(get<i>(*this), get<i>(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues of Ti with i being index(). If an exception is thrown during the exchange of the values of *this and rhs, the states of the values of *this and of rhs are determined by the exception safety guarantee of variant's move constructor and move assignment operator. The expression inside noexcept is equivalent to the logical AND of is_nothrow_move_constructible_v<Ti> && is_nothrow_swappable_v<Ti> for all i.

  2. Modify [variant.specalg] as indicated:

    template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);
    

    -1- Effects: Equivalent to v.swap(w).

    -2- Remarks: This function shall not participate in overload resolution unless is_move_constructible_v<Ti> && is_move_assignable_v<Ti> && is_swappable_v<Ti> is true for all i. The expression inside noexcept is equivalent to noexcept(v.swap(w)).

Date: 2016-07-19.00:00:00

variant does not play nice with swappable traits, the non-member specialized swap overload is not SFINAE friendly. On the other hand, the member swap is SFINAE friendly, albeit with an incomplete condition, when arguably it shouldn't be. Given the Effects, Throws, and Remarks clauses, the SFINAE condition should include is_move_constructible_v and is_move_assignable_v to account for the involvement of variant's move constructor and move assignment operator (the noexcept specification is correct as is, since the move assignment operator would only be called for variants with different alternatives). This SFINAE condition should apply to the non-member swap overload, while the member swap should require all alternatives are swappable (as defined by [swappable.requirements]).

History
Date User Action Args
2017-07-30 20:15:43adminsetstatus: wp -> c++17
2016-11-14 03:59:28adminsetstatus: pending -> wp
2016-11-14 03:55:22adminsetstatus: ready -> pending
2016-09-12 04:46:33adminsetmessages: + msg8516
2016-09-12 04:46:33adminsetstatus: open -> ready
2016-08-13 12:44:23adminsetmessages: + msg8485
2016-08-13 12:44:23adminsetstatus: ready -> open
2016-08-06 21:12:20adminsetstatus: new -> ready
2016-08-01 18:34:48adminsetmessages: + msg8287
2016-07-26 19:07:37adminsetmessages: + msg8255
2016-07-19 00:00:00admincreate