<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<title>Adding [nothrow-]swappable traits (Revision 3)</title>

<style type="text/css">
  p {text-align:justify}
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  blockquote.note
  {
   background-color:#E0E0E0;
   padding-left: 15px;
   padding-right: 15px;
   padding-top: 1px;
   padding-bottom: 1px;
  }
</style>
</head><body>
<address style="text-align: left;">
Document number: P0185R1<br/>
Date: 2016-03-01<br/>
Project: Programming Language C++<br/>
Audience: Library Working Group<br/>
Revises: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0185r0.html">P0185R0</a><br/>
Reply-to: <a href="mailto:daniel.kruegler@gmail.com">Daniel Kr&uuml;gler</a>
</address>
<hr>
<h1 style="text-align: center;">Adding [nothrow-]swappable traits, revision 3</h1>

<ul>
<li><a href="#RevisionHistory">Revision History</a></li>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Rationale">Design Rationale Extension II</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Related_Issues">Related Issues</a></li>
<li><a href="#Proposed_resolution">Proposed Resolution</a></li>
<li><a href="#FeatureMacro">Feature-testing Macro</a></li>
<li><a href="#Appendix">Sample Implementation</a></li>
</ul>

<h2><a name="RevisionHistory"></a>Revision History</h2>
<p>
Changes since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0185r0.html">P0185R0</a>:
</p>
<ul>
<li><p>
Upon request from LWG further non-member <tt>swap</tt> overloads have been constrained via <tt>std::is_swappable&lt;&gt;</tt> 
to ensure that the overload set of binary non-member <tt>swap</tt> is consistently constrained.
</p></li>
</ul>
<p>
Changes since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4511.html">N4511</a>:
</p>
<ul>
<li><p>A new C++ library issue occurred (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2554">LWG 2554</a>),
that would be resolved by the resolution in this paper.</p></li>
<li><p>A new library fundamental issue occurred (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2561">LWG 2561</a>),
that could be resolved by the components that are suggested in the resolution in this paper.</p></li>
<li><p>Following the spirit of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0006r0.html">P0006R0</a>,
which had been accepted during the Kona 2015 meeting, this revision also proposes corresponding type trait variable templates.</p></li>
<li><p>
An <a href="#Rationale">additional section</a> is provided that explains why the usage of the trait 
<tt>is_nothrow_swappable&lt;T&gt;::value</tt> in the exception-specification of the array <tt>swap</tt> overload is not only useful 
but actually indeed important.
</p></li>
<li><p>An <a href="#Appendix">example implementation section</a> has been added.</p></li>
</ul>
<p>
Changes since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html">N4426</a>:
</p>
<ul>
<li><p>
During a straw pool vote in Lenexa of the Library Working Group there was a strong consensus for accepting variant 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Proposed_resolution_ext_constrswap">III. Extended + Constrained <tt>swap</tt></a>:

<table border="1">
  <tr>
    <th>none of this</th>
    <th><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Proposed_resolution_min">I minimalistic</a></th>
    <th><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Proposed_resolution_ext">II extended</a></th>
    <th><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Proposed_resolution_ext_constrswap">III extended + constrained swap</a></th>
  </tr>
  <tr>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>9</td>
  </tr>
</table> 

<p>
Therefore this revision provides now a single wording proposal instead of pointing out possible variants.
</p>

</p></li>
<li><p>
An <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Rationale">additional section</a> is provided that explains why the positive result of 
<tt>std::is_swappable&ltstd::string&amp;&amp;&gt;</tt> is not only useful but actually indeed important.
</p></li>

<li><p>
The <i>Proposed Resolution</i> has been extended by a missing edit of the header <tt>&lt;utility&gt;</tt> synopsis.
</p></li>

<li><p>
A new <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html#Related_Issues">Related Issues</a> section has been added that points out a similar problem in the
C++ Extensions for Library Fundamentals working paper.
</p></li>
</ul>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
This proposal suggests to add new type traits <tt>std::is_swappable&lt;T&gt;</tt>, <tt>std::is_swappable_with&lt;T, U&gt;</tt>, 
<tt>std::is_nothrow_swappable&lt;T&gt;</tt>, and <tt>std::is_nothrow_swappable_with&lt;T, U&gt;</tt> as well as their
corresponding variable template counterparts to the header 
<tt>&lt;type_traits&gt;</tt> to resolve the existing library issue
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">LWG 2456</a> 
involving broken <tt>noexcept</tt>-specifications of several member <tt>swap</tt> functions of a number of library components.
<p/>
In addition to that, this paper suggests to specify the two <tt>swap</tt> templates from header <tt>&lt;utility&gt;</tt> as 
<em>constrained</em> templates.  
<p/>
This paper revision does not repeat the section 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4511.html#Rationale">Design Rationale Extension</a>
of it's predecessor (revision 1) <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4511.html">N4511</a> nor does it
repeat contents of it's pre-predecessor <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html">N4426</a>.
<p/>
Please refer to the previous papers regarding general background and (extended) rationale.
</p>
<blockquote class="note">
<p>
<b>Additional note:</b>
<p/>
As part of a recent <a href="https://gcc.gnu.org/viewcvs/gcc?view=revision&amp;revision=232296">libstdc++ fix</a> the two
traits <tt>is_swappable</tt> and <tt>is_nothrow_swappable</tt> had been implemented in libstdc++ (in the implementors namespace)
and the two free <tt>std::swap</tt> templates have been successfully constrained according to the specification suggested 
by this proposal.
</p>
</blockquote>

<h2><a name="Rationale"></a>Design Rationale Extension II</h2>
<p>
In the prevision revision of this paper, the drafting notes in bullet 2 of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4511.html#Proposed_resolution">the proposed resolution</a>
only <em>recommended</em> to replace the current expression 
</p>
<blockquote><pre>
noexcept(swap(*a, *b))
</pre></blockquote>
<p>
by the <em>seemingly</em> equivalent form
</p>
<blockquote><pre>
is_nothrow_swappable&lt;T&gt;::value
</pre></blockquote>
<p>
within the existing <tt>noexcept</tt>-specification of the <tt>swap</tt> overload for arrays:
</p>
<blockquote><pre>
template &lt;class T, size_t N&gt; void swap(T (&amp;a)[N], T (&amp;b)[N]) noexcept(<span style="color:#C80000;font-weight:bold">noexcept(swap(*a, *b))</span>);
</pre></blockquote>
<p>
pointing out that this would be more or less only an implementation detail.
<p/>
With the appearance of a more recent library issue (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2554">LWG 2554</a>),
new light had been shed on this matter and the author of this paper now considers the usage of the type trait expression
<tt>is_nothrow_swappable&lt;T&gt;::value</tt> as an <em>essential</em> part of the proposed wording.
<p/>
Due to the lookup rules of declarations, the expression <tt>swap(*a, *b)</tt> is part of a yet not completed function declaration, 
therefore at this point the compiler only sees the first (non-array) <tt>swap</tt> overload whose own exception-specification is 
determined by the expression
</p>
<blockquote><pre>
is_nothrow_move_constructible&lt;T&gt;::value &amp;&amp;
is_nothrow_move_assignable&lt;T&gt;::value
</pre></blockquote>
<p>
But since any array type <tt>T</tt> neither meets <tt>is_move_constructible&lt;T&gt;</tt> nor <tt>is_move_assignable&lt;T&gt;</tt>,
the <tt>noexcept</tt>-specification <em>always</em> evaluates to <tt>false</tt>.
<p/>
If instead the type traits expression <tt>is_nothrow_swappable&lt;T&gt;::value</tt> is used, the lookup includes the array 
<tt>swap</tt> as well.
</p>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If the proposed resolution would be accepted, the following library issues will be resolved:
</p>
<table border="1">
  <tr>
    <th>Number</th>
    <th>Description</th>
  </tr>
  <tr>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">2456</a></td>
    <td>Incorrect exception specifications for '<tt>swap</tt>' throughout library</td>
  </tr>
  <tr>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2554">2554</a></td>
    <td>Swapping multidimensional arrays is never <tt>noexcept</tt></td>
  </tr>
</table> 

<h2><a name="Related_Issues"></a>Related Issues</h2>
<p>
The current <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4480.html">C++ Extensions for Library Fundamentals</a> 
is affected by very same problems compared to those pointed out in 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">LWG 2456</a>. 
For example, the specification of <tt>std::experimental::optional</tt>'s member <tt>swap</tt> in 5.3.4 [optional.object.swap] is:
</p>
<blockquote>
<pre>
void swap(optional&lt;T&gt;&amp; rhs) noexcept(<i>see below</i>);
</pre>
</blockquote>
<p>
with:
</p>
<blockquote>
<p>
<i>Remarks</i>: The expression inside <tt>noexcept</tt> is equivalent to: 
</p>
<blockquote>
<pre>
is_nothrow_move_constructible_v&lt;T&gt; &amp;&amp; noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))
</pre>
</blockquote>
</blockquote>
<p>
Another affected example is <tt>propagate_const</tt>'s member <tt>swap</tt> function. 
<p/>
Both these cases are now taken care of by the new library fundamentals issue 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2561">LWG 2561</a>.
<p/>
</p>

<blockquote class="note">
<p>
<b>Albeit solvable by the components suggested by this proposal, this proposal's suggested resolution does <em>not</em> 
provide concrete wording for <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2561">LWG 2561</a>! The
author of this paper would prefer to get the principal idea accepted before attempting to apply it to other working papers.
</b>
</p>
</blockquote>

<h2><a name="Proposed_resolution"></a>Proposed Resolution</h2>

<p>
At some places below, additional markup of the form
</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: whatever &mdash; <i>end drafting notes</i>]
</p>
</blockquote>
<p>
is provided, which is <em>not</em> part of the normative wording, but is solely shown to provide additional information 
to the reader about the rationale of the concrete wording.
</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: This paper generally uses class template traits instead of variable trait definitions
to express derived normative specifications for the following reasons: 
</p>
<ol>
<li><p>The author plans to write a different proposal that suggests to introduce the new trait predicate combinator
<tt>std::conjunction/disjunction</tt> in all specification places where multiple compile-time conditions occur to require short circuit
evaluation whereever possible, but the non-lazy evaluation of variable templates within n-ary expression
would defeat that purpose, while class templates based traits are (currently) more suitable to realize this.</p></li>
<li><p>For technical reasons the author considers class template traits as the more fundamental ("primary") form to define a 
trait. If the working draft editor considers the introduction of variable templates as editorially preferrable, he is anyway free
to rephrase the proposed wording changes.</p></li>
<li><p>There are currently still some relevant core language issues open in regard to variable templates (such as CWG 1729 or CWG 1845),
and the author therefore didn't want to setup a Library specification that might depend on possibly surprising outcomes of these
issues.</p></li>
</ol>
<p>
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<p>
The proposed wording changes refers to the Standard C++ working draft 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4567.pdf">N4567</a>.
</p>

<ol>
<li><p>Change header <tt>&lt;utility&gt;</tt> synopsis, 20.2 [utility] p2, as indicated:</p>

<blockquote>
<pre>
[&hellip;]
<i>// 20.2.2, swap:</i>
template&lt;class T> void swap(T&amp; a, T&amp; b) noexcept(<em>see below</em>);
template&lt;class T, size_t N&gt; void swap(T (&amp;a)[N], T (&amp;b)[N]) noexcept(<ins>is_nothrow_swappable&lt;T&gt;::value</ins><del>noexcept(swap(*a, *b))</del>);
[&hellip;]
</pre>
</blockquote>

</li>

<li><p>Change 20.2.2 [utility.swap] as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>:
</p>
<ol>
<li><p>The <i>Requires</i> elements have been left intentionally, 
based on the assumption that the additional semantic constraints implied by the <tt>MoveConstructible</tt>
and <tt>MoveAssignable</tt> are important to keep.</p></li>
<li><p>The seemingly recursive relation between the <tt>is_[nothrow_]swappable</tt> trait definitions and
especially of the second <tt>swap</tt> declaration is resolvable for a concrete implementation by a suitable sequence 
of (non-defining) declarations of type trait templates and function templates (see the 
<a href="#Appendix">example implementation</a>).</p></li>
</ol>
<p>&mdash; <i>end drafting notes</i>]</p>
</blockquote>

<blockquote>
<pre>
template&lt;class T&gt; void swap(T&amp; a, T&amp; b) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-1- <i>Remark<ins>s</ins></i>: <ins>This function shall not participate in overload resolution unless 
<tt>is_move_constructible&lt;T&gt;::value</tt> is <tt>true</tt> and <tt>is_move_assignable&lt;T&gt;::value</tt> 
is <tt>true</tt>.</ins> The expression inside <tt>noexcept</tt> is equivalent to:
</p>
<blockquote><pre>
is_nothrow_move_constructible&lt;T&gt;::value &amp;&amp;
is_nothrow_move_assignable&lt;T&gt;::value
</pre></blockquote>
<p>
-2- <i>Requires</i>: Type <tt>T</tt> shall be <tt>MoveConstructible</tt> (Table 20) and <tt>MoveAssignable</tt> (Table 22).
<p/>
-3- <i>Effects</i>: [&hellip;]
</p>
</blockquote>
<pre>
template&lt;class T, size_t N&gt;
  void swap(T (&amp;a)[N], T (&amp;b)[N]) noexcept(<ins>is_nothrow_swappable&lt;T&gt;::value</ins><del>noexcept(swap(*a, *b))</del>);
</pre>
<blockquote>
<p>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless <tt>is_swappable&lt;T&gt;::value</tt>
is <tt>true</tt>.</ins>
<p/>
-4- <i>Requires</i>: <tt>a[i]</tt> shall be swappable with (17.6.3.2) <tt>b[i]</tt> for all <tt>i</tt> in the range <tt>[0, N)</tt>.
<p/>
-5- <i>Effects</i>: <tt>swap_ranges(a, a + N, b)</tt>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 20.3.2 [pairs.pair] as indicated:</p>

<blockquote>
<pre>
void swap(pair&amp; p) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-28- <i>Remarks</i>: The expression inside <tt>noexcept</tt> is equivalent to:
</p>
<blockquote>
<pre>
<ins>is_nothrow_swappable&lt;first_type&gt;::value</ins><del>noexcept(swap(first, p.first))</del> &amp;&amp;
<ins>is_nothrow_swappable&lt;second_type&gt;::value</ins><del>noexcept(swap(second, p.second))</del>
</pre>
</blockquote>
<p>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 20.3.3 [pairs.spec] 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>: <tt>x.swap(y)</tt>
<p/>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;T1&gt;::value</tt> is <tt>true</tt> and <tt>is_swappable&lt;T2&gt;::value</tt> is <tt>true</tt>.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p><a name="tuple_swap"></a>Change 20.4.2.3 [tuple.swap] as indicated:</p>

<blockquote>
<pre>
void swap(tuple&amp; rhs) noexcept(<i>see below</i>);
</pre>
<blockquote>
<p>
-1- <i>Remarks</i>: The expression inside <tt>noexcept</tt> is equivalent to the logical <span style="font-variant:small-caps">and</span> 
of the following expressions:
</p>
<blockquote>
<pre>
<ins>is_nothrow_swappable&lt;<em>T<sub>i</sub></em>&gt;::value</ins><del>noexcept(swap(declval&lt;<em>T<sub>i</sub></em>&amp;&gt;&gt;(), declval&lt;<em>T<sub>i</sub></em>&amp;&gt;()))</del>
</pre>
</blockquote>
<p>
where <tt><em>T<sub>i</sub></em></tt> is the <tt><em>i</em></tt><sup>th</sup> type in <tt>Types</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 20.4.2.9 [tuple.special] 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>: <ins>This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;<i>T</i><sub><i>i</i></sub>&gt;::value</tt> is <tt>true</tt> for all <tt><i>i</i></tt>, where 
<tt>0 &lt;= <i>i</i></tt> and <tt><i>i</i> &lt; sizeof...(Types)</tt>.</ins> The expression inside <tt>noexcept</tt> 
is equivalent to:
</p>
<blockquote>
<pre>
noexcept(x.swap(y))
</pre>
</blockquote>
<p>
-2- <i>Effects</i>: <tt>x.swap(y)</tt>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 20.8.1.5 [unique.ptr.special] as indicated:</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: The general requirements of the deleter don't imply <i>swappable</i>, see
20.8.1.2.5 [unique.ptr.single.modifiers] p6, but this is guaranteed to hold for <tt>pointer</tt> due to
<tt>NullablePointer</tt> requirements. &mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<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>Remarks</i>: This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;D&gt;::value</tt> is <tt>true</tt>.</ins>
<p/>
-1- <i>Effects</i>: Calls <tt>x.swap(y)</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 20.10.2 [meta.type.synop], header <tt>&lt;type_traits&gt;</tt> synopsis, as indicated:</p>

<blockquote>
<pre>
namespace std {
  [&hellip;]
  <i>// 20.10.4.3, type properties:</i>
  [&hellip;]
  template &lt;class T&gt; struct is_move_assignable;
  
  <ins>template &lt;class T, class U&gt; struct is_swappable_with;</ins>
  <ins>template &lt;class T&gt; struct is_swappable;</ins>
  
  template &lt;class T&gt; struct is_destructible;
  [&hellip;]
  template &lt;class T&gt; struct is_nothrow_move_assignable;

  <ins>template &lt;class T, class U&gt; struct is_nothrow_swappable_with;</ins>
  <ins>template &lt;class T&gt; struct is_nothrow_swappable;</ins>
  
  template &lt;class T&gt; struct is_nothrow_destructible;
  [&hellip;]

  // 20.10.4.3, type properties
  template &lt;class T&gt; constexpr bool is_const_v
    = is_const&lt;T&gt;::value;
  [&hellip;]
  template &lt;class T&gt; constexpr bool is_move_assignable_v
    = is_move_assignable&lt;T&gt;::value;
  <ins>template &lt;class T, class U&gt; constexpr bool is_swappable_with_v
    = is_swappable_with&lt;T, U&gt;::value;
  template &lt;class T&gt; constexpr bool is_swappable_v
    = is_swappable&lt;T&gt;::value;</ins>
  template &lt;class T&gt; constexpr bool is_destructible_v
    = is_destructible&lt;T&gt;::value;
  [&hellip;]
  template &lt;class T&gt; constexpr bool is_nothrow_move_assignable_v
    = is_nothrow_move_assignable&lt;T&gt;::value;
  <ins>template &lt;class T, class U&gt; constexpr bool is_nothrow_swappable_with_v
    = is_nothrow_swappable_with&lt;T, U&gt;::value;
  template &lt;class T&gt; constexpr bool is_nothrow_swappable_v
    = is_nothrow_swappable&lt;T&gt;::value;</ins>
  template &lt;class T&gt; constexpr bool is_nothrow_destructible_v
    = is_nothrow_destructible&lt;T&gt;::value;
  [&hellip;]
}
</pre>
</blockquote>
</li>

<li><p>Change 20.10.4.3 [meta.unary.prop], Table 49 &mdash; "Type property predicates", as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>:
</p> 
<ol>
<li><p>
The term <i>referenceable type</i>, referred to below, is defined in 17.3.19 [defns.referenceable].</p></li>
<li><p>The specification below allows, but does not require, that an implementation defines the traits
<tt>is_swappable</tt> and <tt>is_nothrow_swappable</tt>, respectively, in terms of the implementation details of the 
more general traits <tt>is_swappable_with</tt> and <tt>is_nothrow_swappable_with</tt>, respectively.</p></li>
</ol>
<p>
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote>
<table border="1">
<caption>Table 49 &mdash; Type property predicates</caption>
<tr>
<th align="center">Template</th>
<th align="center">Condition</th>
<th align="center">Preconditions</th>
</tr>

<tr>
<td colspan="3" align="center">
<tt>&hellip;</tt>
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class T, class U&gt;<br/>
struct is_swappable_with;</tt></ins>
</td>

<td>
<ins>The expressions <tt>swap(declval&lt;T&gt;(), declval&lt;U&gt;())</tt> and<br/>
<tt>swap(declval&lt;U&gt;(), declval&lt;T&gt;())</tt> are each well-formed<br/> 
when treated as an unevaluated operand (Clause 5) in an overload-resolution<br/>
context for swappable values (17.6.3.2 [swappable.requirements]). Access<br/> 
checking is performed as if in a context unrelated to <tt>T</tt> and <tt>U</tt>. Only the<br/> 
validity of the immediate context of the <tt>swap</tt> expressions is considered.<br/>
[<i>Note</i>: The compilation of the expressions can result in side effects such<br/>
as the instantiation of class template specializations and function template<br/>
specializations, the generation of implicitly-defined functions, and so on. Such<br/>
side effects are not in the "immediate context" and can result in the program<br/>
being ill-formed. &mdash; <i>end note</i>]</ins>
</td>

<td>
<ins><tt>T</tt> and <tt>U</tt> shall be complete types,<br/> 
(possibly <i>cv</i>-qualified) <tt>void</tt>, or<br/>
arrays of unknown bound.</ins>
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class T&gt;<br/>
struct is_swappable;</tt></ins>
</td>

<td>
<a name="is_swappable_spec"></a><ins>For a referenceable type <tt>T</tt>, the same result<br/>
as <tt>is_swappable_with&lt;T&amp;, T&amp;&gt;::value</tt>,<br/> 
otherwise <tt>false</tt>.</ins>
</td>

<td>
<ins><tt>T</tt> shall be a complete type,<br/> 
(possibly <i>cv</i>-qualified) <tt>void</tt>, or an<br/>
array of unknown bound.</ins>
</td>
</tr>

<tr>
<td colspan="3" align="center">
<tt>&hellip;</tt>
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class T, class U&gt;<br/>
struct is_nothrow_swappable_with;</tt></ins>
</td>

<td>
<ins><tt>is_swappable_with&lt;T, U&gt;::value</tt> is <tt>true</tt><br/> 
and each <tt>swap</tt> expression of the definition of<br/> 
<tt>is_swappable_with&lt;T, U&gt;</tt> is known not to throw<br/>
any exceptions (5.3.7 [expr.unary.noexcept]).</ins>
</td>

<td>
<ins><tt>T</tt> and <tt>U</tt> shall be complete types,<br/> 
(possibly <i>cv</i>-qualified) <tt>void</tt>, or<br/>
arrays of unknown bound.</ins>
</td>
</tr>

<tr>
<td>
<ins><tt>template &lt;class T&gt;<br/>
struct is_nothrow_swappable;</tt></ins>
</td>

<td>
<ins>For a referenceable type <tt>T</tt>, the same result<br/>
as <tt>is_nothrow_swappable_with&lt;T&amp;, T&amp;&gt;::value</tt>,<br/> 
otherwise <tt>false</tt>.</ins>
</td>

<td>
<ins><tt>T</tt> shall be a complete type,<br/> 
(possibly <i>cv</i>-qualified) <tt>void</tt>, or an<br/>
array of unknown bound.</ins>
</td>
</tr>

<tr>
<td colspan="3" align="center">
<tt>&hellip;</tt>
</td>
</tr>

</table>
</blockquote>

</li>

<li><p>Change 23.3.2.1 [array.overview] p3, class template <tt>array</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class T, size_t N&gt;
  struct array 
  {
    [&hellip;]
    void swap(array&amp;) noexcept(<ins>is_nothrow_swappable&lt;T&gt;::value</ins><del>noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.3.2.3 [array.special] as indicated:</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: 23.3.2.8 [array.zero] does specify that the zero-sized <tt>array</tt> shall have an
<em>unconditional</em> <tt>noexcept(true)</tt> exception specification, which implies that there is no 
reason to constrain it for <tt>N == 0</tt>. I decided to add the (relaxed) constraint here, because it was
much harder to express in 23.3.2.8 [array.zero]. &mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<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>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless <tt>N == 0</tt> or
<tt>is_swappable&lt;T&gt;::value</tt> is <tt>true</tt>.</ins>
<p/>
-1- <i>Effects</i>: <tt>x.swap(y)</tt>;
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 23.3.2.7 [array.swap] before p1 as indicated:</p>

<blockquote>
<pre>
void swap(array&amp; y) noexcept(<ins>is_nothrow_swappable&lt;T&gt;::value</ins><del>noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))</del>);
</pre>
</blockquote>
</li>

<li><p>Change 23.4.4.1 [map.overview] p2, class template <tt>map</tt> overview, as indicated:</p>

<blockquote class="note">
<p>
[<i>Drafting notes</i>: According to 23.2.1 [container.requirements.general] p9:
<p/> 
"Lvalues of any <tt>Compare</tt>, <tt>Pred</tt>, or <tt>Hash</tt> types belonging to <tt>a</tt> and <tt>b</tt> shall be 
swappable"
<p/> 
and furthermore:
<p/>
"If <tt>allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value</tt> is <tt>true</tt>, then 
lvalues of type <tt>allocator_type</tt> shall be swappable"
<p/>
(There does not exist a fundamental Swappable requirement of Allocators, see 17.6.3.5 [allocator.requirements] p4)
<p/>
The latter can be transformed into the following conditional constraint:
<p/>
<tt>!allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value || 
is_swappable&lt;allocator_type&gt;::value</tt>
<p/>
It is currently unclear from the specification, whether the above quoted requirements are considered as
<em>general</em> type requirements of <tt>Compare</tt>, <tt>Pred</tt>, <tt>Hash</tt>, and <tt>allocator_type</tt>
or whether they are only imposed for the instantiated <tt>swap</tt> functions. 
<p/>
In the latter case it would
be consistent to make these <tt>swap</tt> functions constrained functions, in the former case not necessarily so.
<p/>
This proposal decided to not add such constraints <em>now</em>, but to defer this suggestion to a future paper.
<p/>
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, class T, class Compare = less&lt;Key&gt;,
            class Allocator = allocator&lt;pair&lt;const Key, T&gt; &gt; &gt;
  class map 
  {
    [&hellip;]
    void swap(map&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Compare&gt;::value</ins><del>noexcept(swap(declval&lt;Compare&amp;&gt;(),declval&lt;Compare&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.4.5.1 [multimap.overview] p2, class template <tt>multimap</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, class T, class Compare = less&lt;Key&gt;,
            class Allocator = allocator&lt;pair&lt;const Key, T&gt; &gt; &gt;
  class multimap 
  {
    [&hellip;]
    void swap(multimap&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Compare&gt;::value</ins><del>noexcept(swap(declval&lt;Compare&amp;&gt;(),declval&lt;Compare&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.4.6.1 [set.overview] p2, class template <tt>set</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, class Compare = less&lt;Key&gt;,
            class Allocator = allocator&lt;Key&gt; &gt;
  class set 
  {
    [&hellip;]
    void swap(set&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Compare&gt;::value</ins><del>noexcept(swap(declval&lt;Compare&amp;&gt;(),declval&lt;Compare&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.4.7.1 [multiset.overview] p2, class template <tt>multiset</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, class Compare = less&lt;Key&gt;,
            class Allocator = allocator&lt;Key&gt; &gt;
  class multiset 
  {
    [&hellip;]
    void swap(multiset&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Compare&gt;::value</ins><del>noexcept(swap(declval&lt;Compare&amp;&gt;(),declval&lt;Compare&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.5.4.1 [unord.map.overview] p3, class template <tt>unordered_map</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, 
            class T,
            class Hash = hash&lt;Key&gt;,
            class Pred = std::equal_to&lt;Key&gt;,
            class Allocator = std::allocator&lt;std::pair&lt;const Key, T&gt; &gt; &gt;
  class unordered_map 
  {
    [&hellip;]
    void swap(unordered_map&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Hash&gt;::value</ins><del>noexcept(swap(declval&lt;Hash&amp;&gt;(),declval&lt;Hash&amp;&gt;()))</del> &amp;&amp;
               <ins>is_nothrow_swappable&lt;Pred&gt;::value</ins><del>noexcept(swap(declval&lt;Pred&amp;&gt;(),declval&lt;Pred&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.5.5.1 [unord.multimap.overview] p3, class template <tt>unordered_multimap</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, 
            class T,
            class Hash = hash&lt;Key&gt;,
            class Pred = std::equal_to&lt;Key&gt;,
            class Allocator = std::allocator&lt;std::pair&lt;const Key, T&gt; &gt; &gt;
  class unordered_multimap 
  {
    [&hellip;]
    void swap(unordered_multimap&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Hash&gt;::value</ins><del>noexcept(swap(declval&lt;Hash&amp;&gt;(),declval&lt;Hash&amp;&gt;()))</del> &amp;&amp;
               <ins>is_nothrow_swappable&lt;Pred&gt;::value</ins><del>noexcept(swap(declval&lt;Pred&amp;&gt;(),declval&lt;Pred&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.5.6.1 [unord.set.overview] p3, class template <tt>unordered_set</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, 
            class Hash = hash&lt;Key&gt;,
            class Pred = std::equal_to&lt;Key&gt;,
            class Allocator = std::allocator&lt;Key&gt; &gt;
  class unordered_set 
  {
    [&hellip;]
    void swap(unordered_set&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Hash&gt;::value</ins><del>noexcept(swap(declval&lt;Hash&amp;&gt;(),declval&lt;Hash&amp;&gt;()))</del> &amp;&amp;
               <ins>is_nothrow_swappable&lt;Pred&gt;::value</ins><del>noexcept(swap(declval&lt;Pred&amp;&gt;(),declval&lt;Pred&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.5.7.1 [unord.multiset.overview] p3, class template <tt>unordered_multiset</tt> overview, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class Key, 
            class Hash = hash&lt;Key&gt;,
            class Pred = std::equal_to&lt;Key&gt;,
            class Allocator = std::allocator&lt;Key&gt; &gt;
  class unordered_multiset 
  {
    [&hellip;]
    void swap(unordered_multiset&amp;)
      noexcept(allocator_traits&lt;Allocator&gt;::is_always_equal::value &amp;&amp;
               <ins>is_nothrow_swappable&lt;Hash&gt;::value</ins><del>noexcept(swap(declval&lt;Hash&amp;&gt;(),declval&lt;Hash&amp;&gt;()))</del> &amp;&amp;
               <ins>is_nothrow_swappable&lt;Pred&gt;::value</ins><del>noexcept(swap(declval&lt;Pred&amp;&gt;(),declval&lt;Pred&amp;&gt;()))</del>);
    [&hellip;]
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.6.3.1 [queue.defn] p1, class template <tt>queue</tt> definition, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class T, class Container = deque&lt;T&gt; &gt;
  class queue 
  {
    [&hellip;]
  protected:
    Container c;
    
  public:
    [&hellip;]
    void swap(queue&amp; q) noexcept(<ins>is_nothrow_swappable&lt;Container&gt;::value</ins><del>noexcept(swap(c, q.c))</del>)
    { using std::swap; swap(c, q.c); }
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.6.3.5 [queue.special] 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>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;Container&gt;::value</tt> is <tt>true</tt>.</ins>
<p/>
-1- <i>Effects</i>: <tt>x.swap(y)</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 23.6.4 [priority.queue] p1, class template <tt>priority_queue</tt> definition, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class T, class Container = vector&lt;T&gt;,
    class Compare = less&lt;typename Container::value_type&gt; &gt;
  class priority_queue 
  {
    [&hellip;]
  protected:
    Container c;
    Compare comp;
    
  public:
    [&hellip;]
    void swap(priority_queue&amp; q) noexcept(
        <ins>is_nothrow_swappable&lt;Container&gt;::value &amp;&amp; is_nothrow_swappable&lt;Compare&gt;::value</ins>
        <del>noexcept(swap(c, q.c)) &amp;&amp; noexcept(swap(comp, q.comp))</del>)
      { using std::swap; swap(c, q.c); swap(comp, q.comp); }
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.6.4.4 [priqueue.special] as indicated:</p>
<blockquote class="note">
<p>
[<i>Drafting notes</i>: The container adaptors are <em>not</em> containers, so we play safe here and impose
constraints on <tt>Compare</tt> regardless of whether we want these for real container types
&mdash; <i>end drafting notes</i>]
</p>
</blockquote>

<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>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;Container&gt;::value</tt> is <tt>true</tt> and <tt>is_swappable&lt;Compare&gt;::value</tt> 
is <tt>true</tt>.</ins>
<p/>
-1- <i>Effects</i>: <tt>x.swap(y)</tt>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 23.6.5.2 [stack.defn], class template <tt>stack</tt> definition, as indicated:</p>

<blockquote>
<pre>
namespace std {
  template &lt;class T, class Container = deque&lt;T&gt; &gt;
  class stack 
  {
    [&hellip;]
  protected:
    Container c;
    
  public:
    [&hellip;]
    void swap(stack&amp; s) noexcept(<ins>is_nothrow_swappable&lt;Container&gt;::value</ins><del>noexcept(swap(c, s.c))</del>)
      { using std::swap; swap(c, s.c); }
  };
}
</pre>
</blockquote>
</li>

<li><p>Change 23.6.5.6 [stack.special] 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>
<ins>-?- <i>Remarks</i>: This function shall not participate in overload resolution unless 
<tt>is_swappable&lt;Container&gt;::value</tt> is <tt>true</tt>.</ins>
<p/>
-1- <i>Effects</i>: <tt>x.swap(y)</tt>.
</p>
</blockquote>
</blockquote>
</li>

</ol>

<h2><a name="FeatureMacro"></a>Feature-testing Macro</h2>
<p>
For the purposes of SG10, this paper recommends the macro name <tt>__cpp_lib_is_swappable</tt>.
</p>

<h2><a name="Appendix"></a>Sample Implementation</h2>
<p>
Example implementation for the four <tt>swappable</tt> type trait class templates and the two constrained <tt>swap</tt> overloads.
</p>
<blockquote>
<pre>
#include &lt;cstddef&gt;     // std::size_t
#include &lt;type_traits&gt; // std::enable_if, ...
#include &lt;utility&gt;     // std::move, std::declval

namespace xstd {

template&lt;class T&gt;
struct is_swappable;

template&lt;class T&gt;
struct is_nothrow_swappable;

template&lt;class T, class U&gt;
struct is_swappable_with;

template&lt;class T, class U&gt;
struct is_nothrow_swappable_with;

template&lt;class T&gt;
inline
typename std::enable_if&lt;
  std::is_move_constructible&lt;T&gt;::value &amp;&amp;
  std::is_move_assignable&lt;T&gt;::value
&gt;::type
swap(T&amp; a, T&amp; b) noexcept(std::is_nothrow_move_constructible&lt;T&gt;::value &amp;&amp;
                          std::is_nothrow_move_assignable&lt;T&gt;::value);

template&lt;class T, std::size_t N&gt;
inline
typename std::enable_if&lt;
  is_swappable&lt;T&gt;::value
&gt;::type
swap(T (&amp;a)[N], T (&amp;b)[N]) noexcept(is_nothrow_swappable&lt;T&gt;::value);

namespace swappable_details {

using xstd::swap;

struct do_is_swappable
{
  template&lt;class T, class =
    decltype(swap(std::declval&lt;T&amp;&gt;(), std::declval&lt;T&amp;&gt;()))
  &gt;
  static std::true_type test(int);

  template&lt;class&gt;
  static std::false_type test(...);
};

struct do_is_nothrow_swappable
{
  template&lt;class T&gt;
  static auto test(int) -&gt; std::integral_constant&lt;bool,
    noexcept(swap(std::declval&lt;T&amp;&gt;(), std::declval&lt;T&amp;&gt;()))
  &gt;;

  template&lt;class&gt;
  static std::false_type test(...);
};

struct do_is_swappable_with
{
  template&lt;class T, class U
  , class =
    decltype(swap(std::declval&lt;T&gt;(), std::declval&lt;U&gt;()))
  , class =
    decltype(swap(std::declval&lt;U&gt;(), std::declval&lt;T&gt;()))
  &gt;
  static std::true_type test(int);

  template&lt;class, class&gt;
  static std::false_type test(...);
};

struct do_is_nothrow_swappable_with
{
  template&lt;class T, class U&gt;
  static auto test(int) -&gt; std::integral_constant&lt;bool,
    noexcept(swap(std::declval&lt;T&gt;(), std::declval&lt;U&gt;()))
    &&
    noexcept(swap(std::declval&lt;U&gt;(), std::declval&lt;T&gt;()))
  &gt;;

  template&lt;class, class&gt;
  static std::false_type test(...);
};

template&lt;class T&gt;
struct is_swappable_impl : decltype(
  do_is_swappable::test&lt;T&gt;(0)
)
{};

template&lt;class T&gt;
struct is_nothrow_swappable_impl : decltype(
  do_is_nothrow_swappable::test&lt;T&gt;(0)
)
{};

template&lt;class T, class U&gt;
struct is_swappable_with_impl : decltype(
  do_is_swappable_with::test&lt;T, U&gt;(0)
)
{};

// The following specialization is just a QoI optimization and
// not actually required:
<span style="color:#3399FF;font-weight:bold">template&lt;class T&gt;
struct is_swappable_with_impl&lt;T&amp;, T&amp;&gt; : decltype(
  do_is_swappable::test&lt;T&amp;&gt;(0)
)
{};</span>

template&lt;class T, class U&gt;
struct is_nothrow_swappable_with_impl : decltype(
  do_is_nothrow_swappable_with::test&lt;T, U&gt;(0)
)
{};

// The following specialization is just a QoI optimization and
// not actually required:
<span style="color:#3399FF;font-weight:bold">template&lt;class T&gt;
struct is_nothrow_swappable_with_impl&lt;T&amp;, T&amp;&gt; : decltype(
  do_is_nothrow_swappable::test&lt;T&amp;&gt;(0)
)
{};</span>

} // swappable_details

template&lt;class T&gt;
struct is_swappable : swappable_details::is_swappable_impl&lt;T&gt;
{
};

template&lt;class T&gt;
struct is_nothrow_swappable : swappable_details::is_nothrow_swappable_impl&lt;T&gt;
{
};

template&lt;class T, class U&gt;
struct is_swappable_with : swappable_details::is_swappable_with_impl&lt;T, U&gt;
{
};

template&lt;class T, class U&gt;
struct is_nothrow_swappable_with : swappable_details::is_nothrow_swappable_with_impl&lt;T, U&gt;
{
};

template&lt;class T&gt;
inline
typename std::enable_if&lt;
  std::is_move_constructible&lt;T&gt;::value &amp;&amp;
  std::is_move_assignable&lt;T&gt;::value
>::type
swap(T&amp; a, T&amp; b) noexcept(std::is_nothrow_move_constructible&lt;T&gt;::value &amp;&amp;
                          std::is_nothrow_move_assignable&lt;T&gt;::value)
{
  T tmp = std::move(a);
  a = std::move(b);
  b = std::move(tmp);
}

template&lt;class T, std::size_t N&gt;
inline
typename std::enable_if&lt;
  is_swappable&lt;T&gt;::value
&gt;::type
swap(T (&amp;a)[N], T (&amp;b)[N]) noexcept(is_nothrow_swappable&lt;T&gt;::value)
{
  for (std::size_t i = 0; i != N; ++i)
  {
    using xstd::swap;
    swap(a[i], b[i]);
  }
}

} // xstd
</pre>
</blockquote>

</body></html>