<!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</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: N4426<br>
Date: 2015-04-10<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</h1>

<ul>
<li><a href="#Discussion">Discussion</a></li>
<li><a href="#Intro">Introduction</a></li>
<li><a href="#Rationale">Design Rationale</a></li>
<li><a href="#Issues_Resolved">Resolved Issues</a></li>
<li><a href="#Proposed_resolutions">Proposed Resolutions</a>
<ul>
<li><a href="#Proposed_resolution_min">I. Minimalistic</a></li>
<li><a href="#Proposed_resolution_ext">II. Extended</a></li>
<li><a href="#Proposed_resolution_ext_constrswap">III. Extended + Constrained <tt>swap</tt></a></li>
</ul>
</li>
<li><a href="#FeatureMacros">Feature-testing Macros</a></li>
</ul>

<h2><a name="Discussion"></a>Discussion</h2>
<p>
This proposal suggests to add a new type trait <tt>std::is_nothrow_swappable&lt;T&gt;</tt> to the header 
<tt>&lt;type_traits&gt;</tt>. In addition to that this paper provides an <strong>extended resolution</strong> 
that proposes to also add the <tt>std::is_swappable&lt;T&gt;</tt>, <tt>std::is_swappable_with&lt;T, U&gt;</tt>, 
and <tt>std::is_nothrow_swappable_with&lt;T, U&gt;</tt> traits to the header <tt>&lt;type_traits&gt;</tt>.
Finally a <strong>third</strong> even more extended resolution is presented that suggests to specify the two <tt>swap</tt> 
templates from header <tt>&lt;utility&gt;</tt> as <em>constrained</em> templates.  
<p/>
Related papers are the following ones:
</p>
<ul> 
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3048.html">N3048 ("Defining Swappable Requirements")</a></p></li>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3619.html">N3619 ("A proposal to add swappability traits to the standard library")</a></p></li>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3553.pdf">N3553 ("Proposing a C++1Y Swap Operator")</a></p></li>
<li><p><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3746.pdf">N3746 ("Proposing a C++1Y Swap Operator, v2")</a></p></li>
</ul>

<h2><a name="Intro"></a>Introduction</h2>
<p>
This paper attempts 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. It also has the objective to ensure that such an addition 
should be as consistent as possible in regard to existing type traits.
<p/>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">LWG 2456</a> points out that many conditional
<tt>noexcept</tt>-specifications of member-<tt>swap</tt> functions in the library specification are invalid according to the
language rules. As an example consider the class template synopsis of <tt>std::array</tt>:
</p>
<blockquote><pre>
template &lt;class T, size_t N&gt;
struct array 
{
  [&hellip;]
  void swap(array&amp;) noexcept(noexcept(swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;())));
  [&hellip;]
};
</pre></blockquote>
<p>
This exception-specification is ill-formed, because we have an unqualified <tt>swap</tt> expression with two arguments 
occurring within a class-scope that has a member <tt>swap</tt> with one argument, therefore the member <tt>swap</tt> will
be found and as consequence the tested expression can never by found to be valid.
<p/> 
With acceptance of 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1330">CWG 1330</a>
late parsing of exception-specifications had been introduced, so from this point on, a diagnostic is required in this situation,
therefore even a previously possible way to rely on undefined behaviour is no longer possible (and surely never had been a
good foundation for a specification). 
</p>

<h2><a name="Rationale"></a>Design Rationale</h2>
<p>
Assuming we had a suitably defined type trait <tt>is_nothrow_swappable</tt>, the above presented specification of <tt>std::array</tt>'s
member <tt>swap</tt> exception-specification could now be fixed by replacing it by the following form:
</p>
<blockquote><pre>
template &lt;class T, size_t N&gt;
struct array 
{
  [&hellip;]
  void swap(array&amp;) noexcept(is_nothrow_swappable&lt;T&gt;::value);
  [&hellip;]
};
</pre></blockquote>
<p>
This approach would then be similar to other fundamental expression-constraints for copy/move constructions or copy/move
assignments.
<p/>
How many <tt>swap</tt>-related traits should be provided by the Standard Library? 
<p/>
The minimum number is determined by the goal to fix all Library exception-specifications that are affected by above kind of problem.
It turns out that all current <tt>swap</tt> functions in the library that have a conditional <tt>noexcept</tt> specifier do only 
involve swapping of lvalues on objects the same type <tt>T</tt>. That means the Library should at least specify the type trait 
</p>
<blockquote>
<pre>
template &lt;class T&gt; struct is_nothrow_swappable;
</pre>
</blockquote>
<p>
suitable to inspect lvalue swap operations. Currently the library does <em>not</em> define
constrained templates that are constrained in terms of valid <tt>swap</tt> expression (only in combination with <tt>noexcept</tt>
specifiers), therefore the corresponding <tt>is_swappable</tt> trait is technically not <em>required</em> to solve the aforementioned
issue. This lower bound leads us to the <a href="#Proposed_resolution_min">minimalistic resolution</a> discussed in this paper.
<p/>
The maximum number of swappable-traits is determined by the variety of swappable expressions that are categorized by the library. 
The Library supports both homogeneous and heterogeneous <tt>Swappable</tt> requirements as provided by the paper 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3048.html">N3048 ("Defining Swappable Requirements")</a>. The
most general <em>swappable with</em> requirement allows to describe mixed-type swaps and also swap-operations that (partially) involve 
rvalues. Some algorithms (such as <tt>swap_ranges</tt> and <tt>iter_swap</tt>) depend on this more general <em>swappable with</em> 
requirement. Those mixed-type swaps are relevant, for example, if a regular type (such as <tt>bool</tt>) is modeled by a proxy type,
like the member types <tt>std::bitset::reference</tt> or <tt>vector&lt;bool&gt;::reference</tt>. 
Except for such special cases, the majority of <tt>swap</tt> expressions in the library (and in the wild) is restricted to
lvalues of the same type.
<p/>
Therefore the <a href="#Proposed_resolution_ext">extended resolution</a> in this paper suggests to provide the following two type-traits
</p>
<blockquote>
<pre>
template &lt;class T, class U&gt; struct is_swappable_with;
template &lt;class T&gt; struct is_swappable;
</pre>
</blockquote>
<p>
This pair of traits follows the tradition of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3048.html">N3048</a> to
associate these traits to corresponding expression-based requirements from 17.6.3.2 [swappable.requirements] and to the
corresponding swappable concepts from earlier working papers such as 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2914.pdf">N2914</a>:
</p>
<ol>
<li><p><tt>HasSwap&lt;T, U&gt;</tt> &#8660; "<tt>std::declval&lt;T&gt;()</tt> is <strong>swappable with</strong> <tt>std::declval&lt;U&gt;()</tt>" 
&#8660; <tt>is_swappable_with&lt;T, U&gt;::value</tt></p></li>
<li><p><tt>Swappable&lt;T&gt;</tt> &#8660; "<strong>Lvalues</strong> of <tt>T</tt> are <strong>swappable</strong>" 
&#8660; <tt>is_swappable&lt;T&gt;::value</tt></p></li>
</ol>
<p>
For expression-based traits like for operations, that are often used in exception-critical code parts, 
the Library generally distinguishes a trait that describes the well-formedness of an expression
(<tt>is_X</tt>) and in additional to that one that determines whether the very same expression is known <em>not to throw any 
exceptions</em> (<tt>is_nothrow_X</tt>). The latter are relevant for the fixes involving <tt>noexcept</tt>-specifications 
within classes and this leads us to the two remaining traits proposed in the <a href="#Proposed_resolution_ext">extended resolution</a> 
of this paper:
</p>
<blockquote>
<pre>
template &lt;class T, class U&gt; struct is_nothrow_swappable_with;
template &lt;class T&gt; struct is_nothrow_swappable;
</pre>
</blockquote>
<p>
An  <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3619.html">earlier proposal</a> tried to reduce the number
of traits by taking advantage of default template arguments:
</p>
<blockquote>
<pre>
template &lt;class T, class U = T&gt; struct is_swappable;
template &lt;class T, class U = T&gt; struct is_nothrow_swappable;
</pre>
</blockquote>
<p>
Albeit this reduction of declarations looks attractive on the first sight, it is unfortunately easy to use them incorrectly, 
because evaluating <tt>std::is_swappable&lt;T&gt;</tt> does <strong>not</strong> test whether two lvalues of type <tt>T</tt> 
can be swapped, instead it tests whether two <em>rvalues</em> of type <tt>T</tt> can be swapped &mdash; an information that is 
usually not of interest to the programmer. The gotcha effect of this can also be found in  
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3619.html#impact">this section of N3619</a>, where
</p>
<blockquote>
<pre>
static_assert(!is_swappable&lt;X&gt;::value_type);
</pre>
</blockquote>
<p>
should better be written as
</p>
<blockquote>
<pre>
static_assert(!is_swappable&lt;X<span style="color:#C80000;font-weight:bold">&amp;</span>&gt;::value_type);
</pre>
</blockquote>
<p>
Instead this proposal here suggests to use a lengthier name for the more rarely used traits and a shorter name
for the more often used one. The author of this paper is convinced that the asymmetric name <tt>is_swappable_with</tt>
better matches its potentially heterogeneous character. Also, it is <strong>not</strong> suggested (compared to 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3619.html">N3619</a>) to introduce a separate header
for just two or four expression traits: The existing <tt>&lt;type_traits&gt;</tt> header should be feasible for this.
And finally, this proposal does <em>not</em> require that an implementation needs to include 
<tt>&lt;utility&gt;</tt> for the purpose of realizing the required <tt>swap</tt> overload-resolution conditions (In fact,
the non-defining declarations of the two swap templates would be sufficient).
<p/>
Why is it worth providing all these four traits?
<p/>
From a technical point of view these traits can also be provided by non-experts and non-library implementors, albeit 
they require a bit more carefulness compared to other expression-testing traits, because of the special ADL-requirements
of the <tt>Swappable</tt> constraints. As an example, take a look at 
<a href="https://github.com/hostilefork/CopyMoveConstrainedOptional/blob/master/is_swappable.hpp">this freely available code</a>.
<p/>
On the other hand, the author is convinced that <tt>swap</tt> operations have a similar elemental character comparable to move or
copy operations and should therefore be provided even though the Library doesn't yet use all of them within its specification.
This rather fundamental role of <tt>swap</tt> operations has lead to excellent papers from Walter E. Brown, 
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3553.pdf">N3553</a> and its successor
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3746.pdf">N3746</a>, which both contain a good survey about
the basic nature of <tt>swap</tt> operations and even propose to provide built-in operators <tt>:=:</tt>.
<p/>
The provision of the pure expression-validity predicates <tt>is_swappable</tt> and <tt>is_swappable_with</tt> can be considered
as being not much useful given that the two <tt>swap</tt> templates from header <tt>&lt;utility&gt;</tt> are not constrained,
so a lot of false positives are expected to be returned by these traits; those effects have also been analyzed by Andrew Morrow's paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3619.html#impact">N3619</a>.
<p/>
There are two ways of looking at this argument: 
<p/>
First, we would respond to this by suggesting to make these two general
function templates constrained templates, which is the heart of proposal variant 
<a href="#Proposed_resolution_ext_constrswap">III. Extended + Constrained <tt>swap</tt></a>. 
<p/> 
Or alternatively we refer to the fact, that the library does define <tt>is_copy/move_constructible</tt> traits, albeit 
many (if not most) user-provided assignment operators are not constrained (and if we would try to make them constrained in the 
absence of built-in concepts, it is hard to make that possible) and therefore are sensitive to a similar
kind of problem; a well-known example of this are the user-defined copy/move assignment operators of <tt>std::pair</tt> and
<tt>std::tuple</tt>.
<p/>
When considering to constrain the two <tt>swap</tt> templates from header <tt>&lt;utility&gt;</tt> it should be highlighted
that doing this could potentially break existing code. To demonstrate this possibility, consider the following possible
implementation of a constrained <tt>swap</tt> function:
</p>
<blockquote>
<pre>
template&lt;class T&gt;
typename std::enable_if&lt;
  is_move_constructible&lt;T&gt;::value &amp;&amp;
  is_move_assignable&lt;T&gt;::value
>::type 
swap(T&amp; a, T&amp; b) noexcept(
  is_nothrow_move_constructible&lt;T&gt;::value &amp;&amp;
  is_nothrow_move_assignable&lt;T&gt;::value)
{
  T temp = std::move(a);
  a = std::move(b);
  b = std::move(temp);
}
</pre>
</blockquote>
<p>
Lets assume now that some user-defined type <tt>N</tt> exists, that does <em>not</em> satisfy all of its specified
requirements, e.g. it could be non-<tt>MoveAssignable</tt> like this:
</p>
<blockquote>
<pre>
struct N
{
  N&amp; operator=(const N&amp;) = delete;
};
</pre>
</blockquote>
<p>
The owner of <tt>N</tt> could have decided to <em>specialize</em> <tt>std::swap</tt> like this:
</p>
<blockquote>
<pre>
namespace std {

template<>
void swap(N&amp, N&amp) noexcept { [&hellip;] }

}
</pre>
</blockquote>
<p>
Once we would decide to constrain the <tt>swap</tt> template (as shown above), this function specialization will 
no longer compile, because the constraints of the primary template are still applied to the specialization.
<p/>
Is this potential problem an <em>immediate</em> show-stopper?
<p/>
The intuitive answer of many readers is presumably: Yes! &mdash; But for a moment I would like to play the role of 
devil's advocate and present two counter-arguments to this point of view:
</p>
<ol>
<li><p>Strictly speaking, above kind of template specialization can be considered as <strong>invalid</strong>, because
of wording from 17.6.4.2.1 [namespace.std] (emphasis mine):</p>
<blockquote>
<p>
[&hellip;] A program may add a template specialization for any standard library template to namespace <tt>std</tt> <strong>only</strong> 
if the declaration depends on a user-defined type <span style="color:#C80000;font-weight:bold">and the specialization meets 
the standard library requirements for the original template</span> and is not explicitly prohibited.
</p>
</blockquote>
<p>
Obviously, type <tt>N</tt> violates the <tt>MoveAssignable</tt> constraints of the <tt>std::swap</tt> template and this
requirement is not a new one. Nonetheless this code might have worked fine for many years&hellip;
</p>
</li>
<li><p>Furthermore, I would like to remind that C++11 did in fact silently invalidate all existing specializations of 
<tt>std::swap</tt>, which did not have the exact same computed exception-specification of that template, because
in C++03 there was no exception-specification of <tt>std::swap</tt>! So, if there are sufficient good reasons, such
a possible code-breakage can be considered.</p></li>
</ol>
<p>
The author of this paper emphasizes that at this point he needs feedback from Committee members for guidance to
find the best compromise to resolve <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2456">LWG 2456</a>.
This paper presents several choices and he is convinced that at least one of them is acceptable at this point of time, where
the least controversial one (in terms of possible side-effects and implementation costs) surely is the variant denoted as
<a href="#Proposed_resolution_min">"I. Minimalistic"</a>.
</p>

<h2><a name="Issues_Resolved"></a>Resolved Issues</h2>
<p>
If either of the proposed resolutions will 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="Proposed_resolutions"></a>Proposed resolutions</h2>
<blockquote class="note" style="border-style:solid">
<span style="color:#C80000;font-weight:bold">
This paper intentionally does not provide one single resolution proposal. The intention is to
provide to the committee the following selected variants having different advantages and disadvantages.
</span>
</blockquote>
<p>
The proposed wording changes refer in all cases to <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf">N4296</a>.
</p>

<h3><a name="Proposed_resolution_min"></a>I. Minimalistic</h3>
<p>
</p>
<ol>
<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>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_nothrow_move_assignable;

  <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>
<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&gt;<br/>
struct is_nothrow_swappable;</tt></ins>
</td>

<td>
<ins>The expression <tt>swap(declval&lt;T&amp;&gt;(), declval&lt;T&amp;&gt;())</tt> is 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]) and this<br/> 
expression is known not to throw any exceptions (5.3.7 [expr.unary.noexcept]).<br/> 
Access checking is performed as if in a context unrelated to <tt>T</tt>. Only the<br/> 
validity of the immediate context of the <tt>swap</tt> expression is considered.<br/>
[<i>Note</i>: The compilation of the expression 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> 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; 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>
</ol>


<h3><a name="Proposed_resolution_ext"></a>II. Extended</h3>
<p>
The changes are the same as <a href="#Proposed_resolution_min">I. Minimalistic</a>, except for the bullets
(3) and (4) that have to be <em>replaced</em> by the following wording changes:
</p>

<ol start="2">
<li><p>[&hellip;]</p></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].
&mdash; <i>end drafting notes</i>]</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 more general traits 
<tt>is_swappable_with</tt> and <tt>is_nothrow_swappable_with</tt>, respectively.</p></li>
</ol>
</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>
<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>[&hellip;]</p></li>

</ol>

<h3><a name="Proposed_resolution_ext_constrswap"></a>III. Extended + Constrained <tt>swap</tt></h3>
<p>
The changes are the same as <a href="#Proposed_resolution_ext">II. Extended</a>, except that an <em>additional</em>
bullet (18) is added at the end of the list of changes:
</p>

<ol>
<li><p>[&hellip;]</p>
<p>[&hellip;]</p>
</li>
<li value="17"><p>[&hellip;]</p></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 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>
</ol>

<h2><a name="FeatureMacros"></a>Feature-testing Macros</h2>
<p>
For the purposes of SG10, this paper recommends the macro name <tt>__cpp_lib_is_nothrow_swappable</tt>, if the 
<a href="#Proposed_resolution_min">minimalistic resolution</a> would be accepted, or alternatively, 
<tt>__cpp_lib_is_swappable</tt>, if either the <a href="#Proposed_resolution_ext">extended proposal</a> or the
<a href="#Proposed_resolution_ext_constrswap">extended plus constrained <tt>swap</tt></a> would be accepted.
</p>

</body></html>