<!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 1)</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: N4511<br/>
Date: 2015-05-22<br/>
Revises: N4426<br/>
Author: Daniel Kr&uuml;gler<br/>
Project: Programming Language C++, Library Working Group<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 1</h1>

<ul>
<li><a href="#RevisionHistory">Revision History</a></li>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Rationale">Design Rationale Extension</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>
</ul>

<h2><a name="RevisionHistory"></a>Revision History</h2>
<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="#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="#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> 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. 
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 contents of it's predecessor <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4426.html">N4426</a>. 
Please refer to the original paper regarding general background and rationale.
</p>

<h2><a name="Rationale"></a>Design Rationale Extension</h2>
<p>
During the Lenexa meeting concerns were expressed that the trait test
</p>
<blockquote>
<pre>
is_swappable&lt;std::string&amp;&amp;&gt;::value
</pre>
</blockquote>
<p>
will evaluate to <tt>true</tt> and this could suggest to the user that rvalues of <tt>std::string</tt> could be swapped.
<p>
So, is that a desired result for this trait?
<p/>
Responding to the last question first: Surprisingly, the answer to that question is "Yes!" &mdash; It is indeed a <em>desired</em> 
outcome of this trait query, which manifests when we reflect upon the effects this trait test result has on
<a href="#tuple_swap"><tt>std::tuple</tt>'s member swap</a>. The <tt>tuple</tt> template is especially noteworthy in this context, 
because it is the <em>only</em> library component that pro-actively supports members that are rvalue references via the factory 
function <tt>forward_as_tuple</tt>:
</p>
<blockquote>
<pre>
template &lt;class... Types&gt;
  constexpr tuple&lt;<span  style="color:#C80000;font-weight:bold">Types&amp;&amp;</span>...&gt; forward_as_tuple(Types&amp;&amp;...) noexcept;
</pre>
</blockquote>
<p>
Let's assume for a moment that the above mentioned trait would evaluate to <tt>false</tt>. This would essentially mean that we would
say that the type <tt>std::tuple&lt;std::string&amp;&amp;&gt;</tt> would <b>not be lvalue-swappable</b>. This is in contradiction to 
the well-defined characteristics of
</p>
<blockquote>
<pre>
void swap(tuple&amp; rhs)
</pre>
</blockquote>
<p>
which is specified as follows:
</p>
<blockquote>
<p>
-2- <i>Requires</i>: Each element in <tt>*this</tt> shall be swappable with (17.6.3.2) the corresponding element in <tt>rhs</tt>.
<p/>
-3- <i>Effects</i>: Calls swap for each element in <tt>*this</tt> and its corresponding element in <tt>rhs</tt>.
</p>
</blockquote>
<p>
The wording essentially describes that two <b>lvalues</b> which are declared as <b><tt>std::string&amp;&amp;</tt></b> are swapped. 
Conceptually this can be written as
</p>
<blockquote>
<pre>
std::string&amp;&amp; a = ...;
std::string&amp;&amp; b = ...;
using std::swap;
swap(a, b);
</pre>
</blockquote>
<p>
The above example presents more clearly that we are not talking about an attempt of swapping <em>rvalues</em>, but we are still
talking about swapping of <em>lvalues</em>.
<p/>
In other words: A possible pictorial way of describing what <tt>is_swappable&lt;T&amp;&amp;&gt;::value</tt> is asking for a given object 
type <tt>T</tt> is as follows:
</p>
<blockquote class="note">
<p>
Two lvalues that are rvalue-references of type <tt>T</tt> are swappable.
</p>
</blockquote>
<p>
Looking at this phrase a second time it turns out that the part "that are rvalue-references" is completely non-essential and can be
removed giving us the usual way of saying it as
</p>
<blockquote class="note">
<p>
Two lvalues of type <tt>T</tt> are swappable.
</p>
</blockquote>
<p>
This "word-collapsing" corresponds to the same mechanics as the well-known "reference-collapsing" rule that is the foundation of
the <a href="#is_swappable_spec">specification of the trait <tt>is_swappable</tt></a> in the proposed wording below, when <tt>T</tt>
corresponds to any sort of reference type.
<p/>
Is this astonishing characteristics of the <tt>is_swappable</tt> specification unique among the other traits and should therefore
be considered as hard-to-teach?
<p/>
The author of this paper considers this case as not unique. The sometimes surprising consequences of reference-collapsing and
"hidden" reference additions in the specification of type-traits is a known <i>gotcha</i>. Two examples are the observation that 
<tt>is_assignable&lt;int, int&gt;::value</tt> returns <tt>false</tt> ("But I can assign two <tt>int</tt>'s, right?") and that 
<tt>is_move_assignable&lt;std::string&amp;&gt;::value</tt> returns <tt>true</tt>, albeit according to common sense we cannot move-assign 
from an lvalue.
</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>
</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 the very same problem as highlighted by <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">LWG 2456</a>. 
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>
The author of this paper is intending to open a new library issue for this problem and to prepare a future proposal 
that suggests the following changes to the <b>C++ Extensions for Library Fundamentals</b>:
</p>
<ol>
<li><p>To add the following new variable templates to header <tt>&lt;experimental/type_traits&gt;</tt>:</p>
<blockquote><pre>
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;
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;
</pre></blockquote>
</li>
<li><p>To change 5.3.4 [optional.object.swap] p.5:</p></li>
<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; <ins>is_nothrow_swappable_v&lt;T&gt;</ins><del>noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;()))</del>
</pre>
</blockquote>
</blockquote>
</ol>

<blockquote class="note">
<p>
<b>The above presented change suggestions are <em>not</em> part of this proposal!</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>
<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>

<p>
The proposed wording changes refers to <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4431.pdf">N4431</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 replacement of the expression <tt>noexcept(swap(*a, *b))</tt> within the <tt>noexcept</tt>-specification
is not a required change, but seems to improve the symmetry between exception-specifications and template
constraints and is therefore recommended by the author. In addition, a similar approach is already necessary in
existing implementation headers when forward declarations of the <tt>swap</tt> templates are provided.</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.</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>
-31- <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><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.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;]
}
</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.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>
<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.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.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>
</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>

</body></html>