<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2766: Swapping non-swappable types</title>
<meta property="og:title" content="Issue 2766: Swapping non-swappable types">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2766.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="2766"><a href="lwg-active.html#2766">2766</a>. Swapping non-swappable types</h3>
<p><b>Section:</b> 22.3.3 <a href="https://wg21.link/pairs.spec">[pairs.spec]</a>, 22.4.12 <a href="https://wg21.link/tuple.special">[tuple.special]</a>, 22.5.10 <a href="https://wg21.link/optional.specalg">[optional.specalg]</a>, 22.6.10 <a href="https://wg21.link/variant.specalg">[variant.specalg]</a>, 20.3.1.6 <a href="https://wg21.link/unique.ptr.special">[unique.ptr.special]</a>, 23.3.3.4 <a href="https://wg21.link/array.special">[array.special]</a>, 23.6.3.6 <a href="https://wg21.link/queue.special">[queue.special]</a>, 23.6.4.5 <a href="https://wg21.link/priqueue.special">[priqueue.special]</a>, 23.6.6.7 <a href="https://wg21.link/stack.special">[stack.special]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Agust&iacute;n K-ballo Berg&eacute; <b>Opened:</b> 2016-08-15 <b>Last modified:</b> 2020-09-06</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#pairs.spec">issues</a> in [pairs.spec].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Related: <a href="lwg-defects.html#2748" title="swappable traits for optionals (Status: C++17)">2748</a><sup><a href="https://cplusplus.github.io/LWG/issue2748" title="Latest snapshot">(i)</a></sup> swappable traits for optionals, <a href="lwg-defects.html#2749" title="swappable traits for variants (Status: C++17)">2749</a><sup><a href="https://cplusplus.github.io/LWG/issue2749" title="Latest snapshot">(i)</a></sup> swappable traits for variants.
</p>
<p>
The adoption of <a href="https://wg21.link/p0185r1">P0185R1</a> "Adding [nothrow-]swappable traits" makes certain 
non-swappable types indirectly swappable. Consider a type defined as follows:
</p>
<blockquote><pre>
struct non_swappable {
  friend void swap(non_swappable&amp;, non_swappable&amp;) = delete;
};

non_swappable ns1, ns2;
using std::swap;
swap(ns1, ns2); // ill-formed

static_assert(std::is_swappable_v&lt;non_swappable&gt; == false); // holds
</pre></blockquote>
<p>
Lvalues of type <code>non_swappable</code> are not swappable, as defined by 16.4.4.3 <a href="https://wg21.link/swappable.requirements">[swappable.requirements]</a>, 
overload resolution selects the deleted function. Consistently, <code>is_swappable_v&lt;non_swappable&gt;</code> yields 
false. It should be noted that since <code>non_swappable</code> is move constructible and move assignable, a qualified 
call to <code>std::swap</code> would be well-formed, even under P0185. Now consider the following snippet:
</p>
<blockquote><pre>
std::tuple&lt;non_swappable&gt; tns1, tns2;
using std::swap;
swap(tns1, tns2); // previously ill-formed, now well-formed

static_assert(std::is_swappable_v&lt;std::tuple&lt;non_swappable&gt;&gt; == false); // fires
</pre></blockquote>
<p>
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.
<p/>
This issue affects all of <code>pair</code>, <code>tuple</code>, <code>unique_ptr</code>, <code>array</code>, <code>queue</code>, 
<code>priority_queue</code>, <code>stack</code>, and should eventually also apply to <code>optional</code> and <code>variant</code>.
</p>


<strong>Previous resolution [SUPERSEDED]:</strong>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n4606">N4606</a>, except when otherwise noted.</p>

<ol>
<li><p>Modify 22.3.3 <a href="https://wg21.link/pairs.spec">[pairs.spec]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class T1, class T2&gt; void swap(pair&lt;T1, T2&gt;&amp; x, pair&lt;T1, T2&gt;&amp; y)
  noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-7- <i>Effects:</i> As if by <code>x.swap(y)</code>.
<p/>
-8- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as 
deleted</ins> unless <code>is_swappable_v&lt;T1&gt;</code> is <code>true</code> and <code>is_swappable_v&lt;T2&gt;</code> 
is <code>true</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.4.12 <a href="https://wg21.link/tuple.special">[tuple.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class... Types&gt;
  void swap(tuple&lt;Types...&gt;&amp; x, tuple&lt;Types...&gt;&amp; y) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_swappable_v&lt;<code>T<sub>i</sub></code>&gt;</code> is <code>true</code> for all <code><i>i</i></code>, where 
<code>0 &lt;= <i>i</i></code> and <code><i>i</i> &lt; sizeof...(Types)</code>. The expression inside <code>noexcept</code> 
is equivalent to:
</p>
<blockquote><pre>
noexcept(x.swap(y))
</pre></blockquote>
<p>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 20.3.1.6 <a href="https://wg21.link/unique.ptr.special">[unique.ptr.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, class D&gt; void swap(unique_ptr&lt;T, D&gt;&amp; x, unique_ptr&lt;T, D&gt;&amp; y) noexcept;
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_swappable_v&lt;D&gt;</code> is <code>true</code>.
<p/>
-2- <i>Effects:</i> Calls <code>x.swap(y)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 23.3.3.4 <a href="https://wg21.link/array.special">[array.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, size_t N&gt;
  void swap(array&lt;T, N&gt;&amp; x, array&lt;T, N&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>N == 0</code> or <code>is_swappable_v&lt;T&gt;</code> is <code>true</code>.
<p/>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 23.6.3.6 <a href="https://wg21.link/queue.special">[queue.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, class Container&gt;
  void swap(queue&lt;T, Container&gt;&amp; x, queue&lt;T, Container&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_swappable_v&lt;Container&gt;</code> is <code>true</code>.
<p/>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 23.6.4.5 <a href="https://wg21.link/priqueue.special">[priqueue.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, class Container, class Compare&gt;
  void swap(priority_queue&lt;T, Container, Compare&gt;&amp; x,
            priority_queue&lt;T, Container, Compare&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <code>Remarks:</code> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_swappable_v&lt;Container&gt;</code> is <code>true</code> and <code>is_swappable_v&lt;Compare&gt;</code> is <code>true</code>.
<p/>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 23.6.6.7 <a href="https://wg21.link/stack.special">[stack.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, class Container&gt;
  void swap(stack&lt;T, Container&gt;&amp; x, stack&lt;T, Container&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_swappable_v&lt;Container&gt;</code> is <code>true</code>.
<p/>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.5.10 <a href="https://wg21.link/optional.specalg">[optional.specalg]</a> as indicated:</p>
<blockquote class="note">
<p>
This change should be performed if and only if LWG <a href="lwg-defects.html#2748" title="swappable traits for optionals (Status: C++17)">2748</a><sup><a href="https://cplusplus.github.io/LWG/issue2748" title="Latest snapshot">(i)</a></sup> is accepted and is against the wording of <a href="lwg-defects.html#2748" title="swappable traits for optionals (Status: C++17)">2748</a><sup><a href="https://cplusplus.github.io/LWG/issue2748" title="Latest snapshot">(i)</a></sup>:
</p>
</blockquote>
<blockquote>
<pre>
template &lt;class T&gt; void swap(optional&lt;T&gt;&amp; x, optional&lt;T&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> Calls <code>x.swap(y)</code>.
<p/>
-2- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_move_constructible_v&lt;T&gt;</code> is <code>true</code> and <code>is_swappable_v&lt;T&gt;</code> is <code>true</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.6.10 <a href="https://wg21.link/variant.specalg">[variant.specalg]</a> as indicated:</p>
<blockquote class="note">
<p>
This change should be performed if and only if LWG <a href="lwg-defects.html#2749" title="swappable traits for variants (Status: C++17)">2749</a><sup><a href="https://cplusplus.github.io/LWG/issue2749" title="Latest snapshot">(i)</a></sup> is accepted and is against the wording of <a href="lwg-defects.html#2749" title="swappable traits for variants (Status: C++17)">2749</a><sup><a href="https://cplusplus.github.io/LWG/issue2749" title="Latest snapshot">(i)</a></sup>:
</p>
</blockquote>
<blockquote>
<pre>
template &lt;class... Types&gt; void swap(variant&lt;Types...&gt;&amp; v, variant&lt;Types...&gt;&amp; w) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> Equivalent to <code>v.swap(w)</code>.
<p/>
-2- <i>Remarks:</i> This function shall <del>not participate in overload resolution</del><ins>be defined as deleted</ins> 
unless <code>is_move_constructible_v&lt;<i>T<sub>i</sub></i>&gt; &amp;&amp; is_swappable_v&lt;<i>T<sub>i</sub></i>&gt;</code> 
is <code>true</code> for all <code><i>i</i></code>. The expression inside <code>noexcept</code> is equivalent to <code>noexcept(v.swap(w))</code>.
</p>
</blockquote>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[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 <i>Remarks</i> elements are repositioned after the <i>Effects</i>.]</i></p>



<p id="res-2766"><b>Proposed resolution:</b></p>
<p>This wording is relative to <a href="https://wg21.link/n4810">N4810</a>.</p>

<ol>
<li><p>Modify 22.3.3 <a href="https://wg21.link/pairs.spec">[pairs.spec]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class T1, class T2&gt;
  constexpr void swap(pair&lt;T1, T2&gt;&amp; x, pair&lt;T1, T2&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-7- <i>Effects:</i> As if by <code>x.swap(y)</code>.
<p/>
-8- <i>Remarks:</i> This function <del>shall not participate in overload resolution</del><ins>is defined as
deleted</ins> unless <code>is_swappable_v&lt;T1&gt;</code> is <code>true</code> and <code>is_swappable_v&lt;T2&gt;</code>
is <code>true</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.4.12 <a href="https://wg21.link/tuple.special">[tuple.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class... Types&gt;
  constexpr void swap(tuple&lt;Types...&gt;&amp; x, tuple&lt;Types...&gt;&amp; y) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-?- <ins><i>Effects:</i> As if by <code>x.swap(y)</code>.</ins>
</p>
<p>
-1- <i>Remarks:</i> This function <del>shall not participate in overload resolution</del><ins>is defined as deleted</ins>
unless <code>is_swappable_v&lt;<code>T<sub>i</sub></code>&gt;</code> is <code>true</code> for all <code><i>i</i></code>, where
<code>0 &lt;= <i>i</i></code> and <code><i>i</i> &lt; sizeof...(Types)</code>. The expression inside <code>noexcept</code>
is equivalent to:
</p>
<blockquote><pre>
noexcept(x.swap(y))
</pre></blockquote>
<p>
-2- <del><i>Effects:</i> As if by <code>x.swap(y)</code>.</del>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.5.10 <a href="https://wg21.link/optional.specalg">[optional.specalg]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T&gt; void swap(optional&lt;T&gt;&amp; x, optional&lt;T&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> Calls <code>x.swap(y)</code>.
<p/>
-2- <i>Remarks:</i> This function <del>shall not participate in overload resolution</del><ins>is defined as deleted</ins>
unless <code>is_move_constructible_v&lt;T&gt;</code> is <code>true</code> and <code>is_swappable_v&lt;T&gt;</code> is <code>true</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 22.6.10 <a href="https://wg21.link/variant.specalg">[variant.specalg]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class... Types&gt; void swap(variant&lt;Types...&gt;&amp; v, variant&lt;Types...&gt;&amp; w) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> Equivalent to <code>v.swap(w)</code>.
<p/>
-2- <i>Remarks:</i> This function <del>shall not participate in overload resolution</del><ins>is defined as deleted</ins>
unless <code>is_move_constructible_v&lt;<i>T<sub>i</sub></i>&gt; &amp;&amp; is_swappable_v&lt;<i>T<sub>i</sub></i>&gt;</code>
is <code>true</code> for all <code><i>i</i></code>. The expression inside <code>noexcept</code> is equivalent to <code>noexcept(v.swap(w))</code>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 20.3.1.6 <a href="https://wg21.link/unique.ptr.special">[unique.ptr.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, class D&gt; void swap(unique_ptr&lt;T, D&gt;&amp; x, unique_ptr&lt;T, D&gt;&amp; y) noexcept;
</pre>
<blockquote>
<p>
-?- <ins><i>Effects:</i> Calls <code>x.swap(y)</code>.</ins>
</p>
<p>
-1- <i>Remarks:</i> This function <del>shall not participate in overload resolution</del><ins>is defined as deleted</ins>
unless <code>is_swappable_v&lt;D&gt;</code> is <code>true</code>.
</p>
<p>
-2- <del><i>Effects:</i> Calls <code>x.swap(y)</code>.</del>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Modify 23.3.3.4 <a href="https://wg21.link/array.special">[array.special]</a> as indicated:</p>
<blockquote>
<pre>
template &lt;class T, size_t N&gt;
  void swap(array&lt;T, N&gt;&amp; x, array&lt;T, N&gt;&amp; y) noexcept(noexcept(x.swap(y)));
</pre>
<blockquote>
<p>
-1- <del><i>Constraints:</i> <code>N == 0</code> or <code>is_swappable_v&lt;T&gt;</code> is <code>true</code>.</del>
<p/>
-2- <i>Effects:</i> As if by <code>x.swap(y)</code>.
<p/>
-3- <i>Complexity:</i> Linear in <code>N</code>.
<p/>
-?- <ins><i>Remarks:</i> This function is defined as deleted
unless <code>N == 0</code> or <code>is_swappable_v&lt;T&gt;</code> is <code>true</code>.</ins>
</p>
</blockquote>
</blockquote>
</li>
</ol>






</body>
</html>
