swappable
traits for variant
sSection: 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 variant
s 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:Ti
shall be swappable andis_move_constructible_v<Ti> && is_move_assignable_v<Ti>
istrue
for alli
.This function shall not participate in overload resolution unlessIf an exception is thrown during the call to functionis_swappable_v<Ti>
istrue
for alli
.swap(get<i>(*this), get<i>(rhs))
, the states of the contained values of*this
and ofrhs
are determined by the exception safety guarantee of swap for lvalues ofTi
withi
beingindex()
. If an exception is thrown during the exchange of the values of*this
andrhs
, the states of the values of*this
and ofrhs
are determined by the exception safety guarantee ofvariant
's move constructor and move assignment operator. The expression insidenoexcept
is 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>
istrue
for alli
. The expression insidenoexcept
is 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 typeTi
shall be swappable andis_move_constructible_v<Ti>
shall betrue
for 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 operatorTi
orTj
withi
beingindex()
andj
beingrhs.index()
. -3- Remarks:This function shall not participate in overload resolution unlessIf an exception is thrown during the call to functionis_swappable_v<Ti>
istrue
for alli
.swap(get<i>(*this), get<i>(rhs))
, the states of the contained values of*this
and ofrhs
are determined by the exception safety guarantee of swap for lvalues ofTi
withi
beingindex()
. If an exception is thrown during the exchange of the values of*this
andrhs
, the states of the values of*this
and ofrhs
are determined by the exception safety guarantee ofvariant
's move constructorand move assignment operator. The expression insidenoexcept
is 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>
istrue
for alli
. The expression insidenoexcept
is equivalent tonoexcept(v.swap(w))
.