Section: 22.3.3 [pairs.spec], 22.4.12 [tuple.special], 22.5.9 [optional.specalg], 22.6.10 [variant.specalg], 20.3.1.6 [unique.ptr.special], 23.3.3.4 [array.special], 23.6.3.6 [queue.special], 23.6.4.5 [priqueue.special], 23.6.6.7 [stack.special] Status: New Submitter: Agustín K-ballo Bergé Opened: 2016-08-15 Last modified: 2020-09-06
Priority: 3
View all other issues in [pairs.spec].
View all issues with New status.
Discussion:
Related: 2748 swappable traits for optionals, 2749 swappable traits for variants.
The adoption of P0185R1 "Adding [nothrow-]swappable traits" makes certain non-swappable types indirectly swappable. Consider a type defined as follows:
struct non_swappable { friend void swap(non_swappable&, non_swappable&) = delete; }; non_swappable ns1, ns2; using std::swap; swap(ns1, ns2); // ill-formed static_assert(std::is_swappable_v<non_swappable> == false); // holds
Lvalues of type non_swappable
are not swappable, as defined by 16.4.4.3 [swappable.requirements],
overload resolution selects the deleted function. Consistently, is_swappable_v<non_swappable>
yields
false. It should be noted that since non_swappable
is move constructible and move assignable, a qualified
call to std::swap
would be well-formed, even under P0185. Now consider the following snippet:
std::tuple<non_swappable> tns1, tns2; using std::swap; swap(tns1, tns2); // previously ill-formed, now well-formed static_assert(std::is_swappable_v<std::tuple<non_swappable>> == false); // fires
Before P0185, this snippet would violate the implicit requirement of specialized swap for tuples that each tuple element be swappable. After P0185, this specialized swap overload for tuples would be SFINAEd away, resulting in overload resolution selecting the base swap overload, and performing the exchange via move construction and move assignment of tuples.
This issue affects all ofpair
, tuple
, unique_ptr
, array
, queue
,
priority_queue
, stack
, and should eventually also apply to optional
and variant
.
Previous resolution [SUPERSEDED]:
This wording is relative to N4606, except when otherwise noted.
Modify 22.3.3 [pairs.spec] as indicated:
template<class T1, class T2> void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));-7- Effects: As if by
-8- Remarks: This function shallx.swap(y)
.not participate in overload resolutionbe defined as deleted unlessis_swappable_v<T1>
istrue
andis_swappable_v<T2>
istrue
.Modify 22.4.12 [tuple.special] as indicated:
template <class... Types> void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);-1- Remarks: This function shall
not participate in overload resolutionbe defined as deleted unlessis_swappable_v<
isTi
>true
for alli
, where0 <= i
andi < sizeof...(Types)
. The expression insidenoexcept
is equivalent to:noexcept(x.swap(y))-2- Effects: As if by
x.swap(y)
.Modify 20.3.1.6 [unique.ptr.special] as indicated:
template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;-1- Remarks: This function shall
-2- Effects: Callsnot participate in overload resolutionbe defined as deleted unlessis_swappable_v<D>
istrue
.x.swap(y)
.Modify 23.3.3.4 [array.special] as indicated:
template <class T, size_t N> void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));-1- Remarks: This function shall
-2- Effects: As if bynot participate in overload resolutionbe defined as deleted unlessN == 0
oris_swappable_v<T>
istrue
.x.swap(y)
. […]Modify 23.6.3.6 [queue.special] as indicated:
template <class T, class Container> void swap(queue<T, Container>& x, queue<T, Container>& y) noexcept(noexcept(x.swap(y)));-1- Remarks: This function shall
-2- Effects: As if bynot participate in overload resolutionbe defined as deleted unlessis_swappable_v<Container>
istrue
.x.swap(y)
.Modify 23.6.4.5 [priqueue.special] as indicated:
template <class T, class Container, class Compare> void swap(priority_queue<T, Container, Compare>& x, priority_queue<T, Container, Compare>& y) noexcept(noexcept(x.swap(y)));-1-
-2- Effects: As if byRemarks:
This function shallnot participate in overload resolutionbe defined as deleted unlessis_swappable_v<Container>
istrue
andis_swappable_v<Compare>
istrue
.x.swap(y)
.Modify 23.6.6.7 [stack.special] as indicated:
template <class T, class Container> void swap(stack<T, Container>& x, stack<T, Container>& y) noexcept(noexcept(x.swap(y)));-1- Remarks: This function shall
-2- Effects: As if bynot participate in overload resolutionbe defined as deleted unlessis_swappable_v<Container>
istrue
.x.swap(y)
.Modify 22.5.9 [optional.specalg] as indicated:
This change should be performed if and only if LWG 2748 is accepted and is against the wording of 2748:
template <class T> void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));-1- Effects: Calls
-2- Remarks: This function shallx.swap(y)
.not participate in overload resolutionbe defined as deleted unlessis_move_constructible_v<T>
istrue
andis_swappable_v<T>
istrue
.Modify 22.6.10 [variant.specalg] as indicated:
This change should be performed if and only if LWG 2749 is accepted and is against the wording of 2749:
template <class... Types> void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);-1- Effects: Equivalent to
-2- Remarks: This function shallv.swap(w)
.not participate in overload resolutionbe defined as deleted unlessis_move_constructible_v<Ti> && is_swappable_v<Ti>
istrue
for alli
. The expression insidenoexcept
is equivalent tonoexcept(v.swap(w))
.
[2019-04-17 Jonathan updates proposed resolution based on Ville's 2016-11-17 observation that the container adaptors always require swappable sequences anyway. The new proposed resolution is based on the latest WP, "de-shalled", and Remarks elements are repositioned after the Effects.]
Proposed resolution:
This wording is relative to N4810.
Modify 22.3.3 [pairs.spec] as indicated:
template<class T1, class T2> constexpr void swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));-7- Effects: As if by
-8- Remarks: This functionx.swap(y)
.shall not participate in overload resolutionis defined as deleted unlessis_swappable_v<T1>
istrue
andis_swappable_v<T2>
istrue
.
Modify 22.4.12 [tuple.special] as indicated:
template <class... Types> constexpr void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(see below);-?- Effects: As if by
x.swap(y)
.-1- Remarks: This function
shall not participate in overload resolutionis defined as deleted unlessis_swappable_v<
isTi
>true
for alli
, where0 <= i
andi < sizeof...(Types)
. The expression insidenoexcept
is equivalent to:noexcept(x.swap(y))-2-
Effects: As if byx.swap(y)
.
Modify 22.5.9 [optional.specalg] as indicated:
template <class T> void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));-1- Effects: Calls
-2- Remarks: This functionx.swap(y)
.shall not participate in overload resolutionis defined as deleted unlessis_move_constructible_v<T>
istrue
andis_swappable_v<T>
istrue
.
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 functionv.swap(w)
.shall not participate in overload resolutionis defined as deleted unlessis_move_constructible_v<Ti> && is_swappable_v<Ti>
istrue
for alli
. The expression insidenoexcept
is equivalent tonoexcept(v.swap(w))
.
Modify 20.3.1.6 [unique.ptr.special] as indicated:
template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;-?- Effects: Calls
x.swap(y)
.-1- Remarks: This function
shall not participate in overload resolutionis defined as deleted unlessis_swappable_v<D>
istrue
.-2-
Effects: Callsx.swap(y)
.
Modify 23.3.3.4 [array.special] as indicated:
template <class T, size_t N> void swap(array<T, N>& x, array<T, N>& y) noexcept(noexcept(x.swap(y)));-1-
-2- Effects: As if byConstraints:N == 0
oris_swappable_v<T>
istrue
.x.swap(y)
. -3- Complexity: Linear inN
. -?- Remarks: This function is defined as deleted unlessN == 0
oris_swappable_v<T>
istrue
.