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.
swappable traits for variantsSection: 22.6.3.7 [variant.swap], 22.6.10 [variant.specalg] Status: C++17 Submitter: Agustín K-ballo Bergé Opened: 2016-07-19 Last modified: 2017-07-30
Priority: 1
View all issues with C++17 status.
Discussion:
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 16.4.4.3 [swappable.requirements]).
[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.
Modify 22.6.3.7 [variant.swap] as indicated:
void swap(variant& rhs) noexcept(see below);-?- Requires: Lvalues of type
[…] -3- Remarks:Tishall be swappable andis_move_constructible_v<Ti> && is_move_assignable_v<Ti>istruefor alli.This function shall not participate in overload resolution unlessIf an exception is thrown during the call to functionis_swappable_v<Ti>istruefor alli.swap(get<i>(*this), get<i>(rhs)), the states of the contained values of*thisand ofrhsare determined by the exception safety guarantee of swap for lvalues ofTiwithibeingindex(). If an exception is thrown during the exchange of the values of*thisandrhs, the states of the values of*thisand ofrhsare determined by the exception safety guarantee ofvariant's move constructor and move assignment operator. The expression insidenoexceptis equivalent to the logical AND ofis_nothrow_move_constructible_v<Ti> && is_nothrow_swappable_v<Ti>for alli.Modify 22.6.10 [variant.specalg] as indicated:
template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);-1- Effects: Equivalent to
-2- Remarks: This function shall not participate in overload resolution unlessv.swap(w).is_move_constructible_v<Ti> && is_move_assignable_v<Ti> && is_swappable_v<Ti>istruefor alli. The expression insidenoexceptis equivalent tonoexcept(v.swap(w)).
[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.
[2016-09-09 Issues Resolution Telecon]
Move to Tentatively Ready
Proposed resolution:
This wording is relative to N4606.
Modify 22.6.3.7 [variant.swap] as indicated:
void swap(variant& rhs) noexcept(see below);-?- Requires: Lvalues of typeTishall be swappable andis_move_constructible_v<Ti>shall betruefor alli. […] -2- Throws: Ifindex() == rhs.index(), aAny exception thrown byswap(get<i>(*this), get<i>(rhs))with i beingindex()and. Otherwise, any exception thrown by the move constructor ofvariant's move constructor and assignment operatorTiorTjwithibeingindex()andjbeingrhs.index(). -3- Remarks:This function shall not participate in overload resolution unlessIf an exception is thrown during the call to functionis_swappable_v<Ti>istruefor alli.swap(get<i>(*this), get<i>(rhs)), the states of the contained values of*thisand ofrhsare determined by the exception safety guarantee of swap for lvalues ofTiwithibeingindex(). If an exception is thrown during the exchange of the values of*thisandrhs, the states of the values of*thisand ofrhsare determined by the exception safety guarantee ofvariant's move constructorand move assignment operator. The expression insidenoexceptis equivalent to the logical AND ofis_nothrow_move_constructible_v<Ti> && is_nothrow_swappable_v<Ti>for alli.
Modify 22.6.10 [variant.specalg] as indicated:
template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);-1- Effects: Equivalent to
-2- Remarks: This function shall not participate in overload resolution unlessv.swap(w).is_move_constructible_v<Ti> && is_swappable_v<Ti>istruefor alli. The expression insidenoexceptis equivalent tonoexcept(v.swap(w)).