<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">

  <meta name ="description" content="Proposal for C++ Standard">
  <meta name ="keywords" content="C++,cplusplus,wg21">
  <meta name ="author" content="Alisdair Meredith">

  <title>Reviewing Deprecated Facilities of C++20 for C++23</title>

  <style>
    body {
      counter-reset: section;
    }

    h2 {
      counter-reset: subsection;
    }

    h2::before {
      counter-increment: section;
      content: counter(section) " ";
    }

    h2.uncounted::before {
      counter-increment: none;
      content: "";
    }

    h3::before {
      counter-increment: subsection;
      content: "D." counter(subsection) " ";
    }

    h3.uncounted::before {
      counter-increment: none;
      content: "";
    }

    ins {background-color:#A0FFA0}
    del {background-color:#FFA0A0}
    p {text-align:justify}
    li {text-align:justify}

    ol.index { counter-reset: item }
    ol.index li { display: block }
    ol.index li:before { content: counters(item, ".") " "; counter-increment: item }

    ul.index { counter-reset: depr }
    ul.index li { display: block }
    ul.index li:before { content: "D." counters(depr, ".") " "; counter-increment: depr }

    blockquote.note
    {
      background-color:#E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.recommend
    {
      background-color:#ffffb0;
      padding-left: 10px;
      padding-right: 10px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.review
    {
      background-color:#c8ffc8;
      padding-left: 10px;
      padding-right: 10px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.review_note
    {
      background-color:#ffffcc;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.draft_wording
    {
      background-color:#f8f8f8;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.old_wording
    {
      background-color:#f8f0f0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    blockquote.proposed_wording
    {
      background-color:#f8f8e8;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }
    tr:nth-child(even) {background-color: #f2f2f2;}

    table.poll tr {background-color: #fcfcfc; text-align:center;}
    table.poll td {width: 20%;}
  </style>
</head>

<body>
<table>
<tr>
  <td>Doc. no.</td>
  <td>P2139R2</td>
</tr>
<tr>
  <td>Date:</td>
  <td>2020-07-15</td>
</tr>
<tr>
  <td>Project:</td>
  <td>Programming Language C++</td>
</tr>
<tr>
  <td>Audience:</td>
  <td>Evolution Working Group Incubator</td>
</tr><tr>
  <td></td>
  <td>Library Evolution Working Group Incubator</td>
</tr>
<tr>
  <td>Reply to:</td>
  <td>Alisdair Meredith &lt;<a href="mailto:ameredith1@bloomberg.net">ameredith1@bloomberg.net</a>&gt;</td>
</tr>
</table>

<h1>Reviewing Deprecated Facilities of C++20 for C++23</h1>

<h2 class="uncounted">Table of Contents</h2>
<ul>
<li><a href="#rev.hist">Revision History</a>
  <ul>
  <li><a href="#rev.2">Revision 2</a></li>
  <li><a href="#rev.1">Revision 1</a></li>
  <li><a href="#rev.0">Original</a></li>
  </ul>
</li>
</ul>

<ol class="index">
<li><a href="#1.0">Abstract</a></li>
<li><a href="#2.0">Stating the problem</a></li>
<li><a href="#3.0">Propose Solution</a>
  <ul class="index">
  <li><a href="#3.1">Arithmetic conversion on enumerations [depr.arith.conv.enum]</a></li>
  <li><a href="#3.2">Implicit capture of <code>*this</code> by reference [depr.capture.this]</a></li>
  <li><a href="#3.3">Comma operator in subscript expressions [depr.comma.subscript]</a></li>
  <li><a href="#3.4">Array comparisons [depr.array.comp]</a></li>
  <li><a href="#3.5">Deprecated volatile types [depr.volatile.type]</a></li>
  <li><a href="#3.6">Redeclaration of static constexpr data members [depr.static_constexpr]</a></li>
  <li><a href="#3.7">Non-local use of TU-local entities [depr.local]</a></li>
  <li><a href="#3.8">Implicit declaration of copy functions [depr.impldec]</a></li>
  <li><a href="#3.9">C headers [depr.c.headers]</a></li>
  <li><a href="#3.10">Requires paragraph [depr.res.on.required]</a></li>
  <li><a href="#3.11">Relational operators [depr.relops]</a></li>
  <li><a href="#3.12"><code>char*</code> streams [depr.str.strstreams]</a></li>
  <li><a href="#3.13">Deprecated type traits [depr.meta.types]</a></li>
  <li><a href="#3.14">Tuple [depr.tuple]</a></li>
  <li><a href="#3.15">Variant [depr.variant]</a></li>
  <li><a href="#3.16">Deprecated iterator primitives [depr.iterator.primitives]</a></li>
  <li><a href="#3.17">Deprecated <code>move_iterator</code> access [depr.move.iter.elem]</a></li>
  <li><a href="#3.18">Deprecated <code>shared_ptr</code> atomic access [depr.util.smartptr.shared.atomic]</a></li>
  <li><a href="#3.19">Deprecated <code>basic_string</code> capacity [depr.string.capacity]</a></li>
  <li><a href="#3.20">Deprecated Standard code conversion facets [depr.locale.stdcvt]</a></li>
  <li><a href="#3.21">Deprecated convience conversion interfaces [depr.conversions]</a></li>
  <li><a href="#3.22">Deprecated locale category facets [depr.locale.category]</a></li>
  <li><a href="#3.23">Deprecated filesystem path factory functions [depr.fs.path.factory]</a></li>
  <li><a href="#3.24">Deprecated atomic operations [depr.atomics]</a></li>
  </ul>
</li>
<li><a href="#4.0">Other Directions</a></li>
<li><a href="#5.0">Formal Wording</a></li>
<li><a href="#6.0">Acknowledgements</a></li>
<li><a href="#7.0">References</a></li>
</ol>


<h2 class="uncounted" id="rev.hist">Revision History</h2>

<blockquote>
<h3 class="uncounted" id="rev.2">Revision 2</h3>
<p>
Revision of the paper for the 2020 July mailing, following telecon feedback.
</p>
<ul>
  <li>
  Fixed whitespace bugs in the grammar for
  <i><code>relational-expression</code></i>
  </li>
  <li>
  Added comment to introduction on general feedback on the topic of removing
  deprecated libraries
  </li>
  <li>
  Record LEWGI feedback from the telecon on 2020-07-13
  </li>
  <li>
  Add initial LEWGI feedback to integrated wording for eventual LWG review
  </li>
  <li>
  Note in D.9 that the next C standard will likely deprecate
  <code>&lt;stdalign.h&gt;</code> and <code>&lt;stdbool.h&gt;</code>
  </li>
  <li>
  Add a note on the historical use of <code>rel_ops</code> in the standard,
  prior to its moving to D.11
  </li>
  <li>
  Provided (without encouragement) wording to undeprecate strstreams in D.12
  </li>
  <li>
  Added cross-reference to the <code>spanstream</code> proposal for D.12
  </li>
  <li>
  For D.13, note that the related term POF was removed from C++17
  </li>
  <li>
  Fix original reason for deprecation in D.14/D.15, which had nothing to do
  with modules!
  </li>
  <li>
  For D.16, add cross-reference to the paper that introduced more
  <code>iterator_traits</code> defaults
  </li>
  <li>
  Note for D.24 that the next C standard will likely remove
  <code>ATOMIC_VAR_INIT</code>
  </li>
</ul>

<h3 class="uncounted" id="rev.1">Revision 1</h3>
<p>
Revision of the paper for the 2020 June mailing, following early feedback.
</p>
<ul>
  <li>
  Clean up document format using a html validator
  </li>
  <li>
  Note which compiler versions start issuing warnings
  </li>
  <li>
  Record EWGI review of subclauses D.1 - D.4.
  </li>
  <li>
  Start collecting integrated wording for eventual core review, where EWGI have
  provided a recommendation.
  </li>
  <li>
  Note that users can work around deprecation in D.1 with a simple unary
  <code>+</code>
  </li>
  <li>
  Update wording for EWGI preference to remove just floating point interaction
  in D.1
  </li>
  <li>
  Propose Annex C wording for D.1
  </li>
  <li>
  Completely revised recommendations for D.3 (comma expressions in array bounds),
  guided by feedback on R0 of this paper.
  </li>
  <li>
  Propose Annex C wording for D.3 following EWGI recommendation to remove.
  </li>
  <li>
  Propose Annex C wording for D.4 following EWGI recommendation to remove.
  </li>
  <li>
  A more fine-grained analysis of D.5 (volatile operations), as this deprecation
  is really four cases in one clause.
  </li>
  <li>
  Initial drafting of core wording to remove D.5, if we so choose.
  </li>
  <li>
  Note that no currently available compiler warns on the deprecation of D.6
  (Redeclare <code>constexpr</code> members)
  </li>
  <li>
  Example of an iterator implementation idiom that requires slightly more work
  to resolve D.8 deprecation.
  </li>
  <li>
  Note that Clang 10 also now warns on the deprecations in D.8.
  </li>
  <li>
  Added a note to D.9 that we expect compilers will never give a deprecation
  warning on the use of these headers
  </li>
  <li>
  For D.10 (library <i>Requires</i> paragraphs), revised suggestion of
  <i>Mandates</i> to <i>Preconditions</i> where both run-time and compile-time
  requirements applied.
  </li>
</ul>

<h3 class="uncounted" id="rev.0">Original</h3>
<p>
Original version of the paper for the 2020 post-Prague mailing.
</p>
</blockquote>


<h2 id="1.0">Abstract</h2>
<p>
This paper evaluates all the existing deprecated facilities in the C++20
standard, and recommends removing a subset from Annex D in C++23, either by
removing from the standard entirely, or by undeprecating and restoring to the
main text.
</p>


<h2 id="2.0">Stating the problem</h2>
<p>
With the release of a new C++ standard, we get an opportunity to revisit the
features identified for deprecation, and consider if we are prepared to clear
any out yet, either by removing completely from the standard, or by reversing
the deprecation decision and restoring the feature to full service.  This paper
makes no attempt to offer proposals for removing features other than those
deprecated in Annex D, nor does it attempt to identify new candidates for
deprecation.
</p>
<p>
In an ideal world, the start of every release cycle would cleanse the list of
deprecated features entirely, allowing the language and library to evolve
cleanly without holding too much deadweight.  This paper is an attempt to
consolidate all likely requests (and papers) to review isolated features on
Annex D, and gain efficiency by performing one consolidated review.  In
practice, C++ has some long-term deprecated facilities that are difficult to
remove, and equally difficult to rehabilitate.  It seems reasonable that work
could be split into follow-up papers if a direction has appeal, but needs more
work for consensus to advance; one possible goal of this paper is to discover
which features we may be interested in following up while maintaining the tempo
of an efficient high level review.
</p>
<p>
The benefits of making the choice to remove features early in a standard cycle
is that we will get the most experience we can from the bleeding-edge adopters
whether a particular removal is more problematic than expected - but even this
data point is limited, as bleeding-edge adopters typically have less reliance
on deprecated features, eagerly adopting the newer replacement facilities.
</p>
<p>
However, do note that with the three year release cadence for the C++ standard,
we will often be re-evaluating features whose deprecated status has barely
reached print.
</p>
<p>
We have precedent that Core language features are good targets for removal,
typically taking two standard cycles to remove a deprecated feature, although
often prepared to entirely remove a feature even without a period of
deprecation, if the cause is strong enough.
</p>
<p>
The library experience has been mixed, with no desire to remove anything
without a period of deprecation (other than <code>gets</code>) and no precedent
prior to C++17 for actually removing deprecated features.
</p>
<p>
The precedent set for the library in C++17 seems to be keener to clear out the
old code more quickly though, even removing features deprecated as recently as
the previous standard, with the ink still drying on the text!  Accordingly,
this paper will be fairly aggressive in its attempt to clear out old libraries.
This is perhaps more reasonable for the library clauses than the core language,
as the Zombie Names clause, <b>16.5.4.3.1 [zombie.names]</b> allows vendors to
continue shipping features long after they have left the standard, as long as
their existing customers rely on them.
</p>
Informal feedback on library deprecation prior to LEWGI review leans in two
directions: deprecation is for life, and we should never remove anything, as
there is no reason for the library to ever break client code; and alternatively
the with the addition of zombie names there is clear intent library vendors
should continue supporting deprecated features as long as their customers
demand them, without violating conformance, and that removal from the standard
removes maintenance costs from wg21 (placed instead on library vendors) and
that this paper should have been stronger in its recommendations to remove.
<p>

</p>

<h2 id="3.0">Proposed Solution</h2>
<p>
We will review each deprecated facility, and make a strong and a weak
recommendation.  The strong recommendation is the preferred direction of the
authors, who lean towards early removal.  There will also be a weak
recommendation, which is an alternative proposal for the evolution groups to
consider, if the strong recommendation does not find favor.  Finally, wording
is generally provided for both the strong and weak recommendations, which will
be collated into a unified Proposed Wording section once the various
recommendations have been given direction by the corresponding evolution group.
</p>
<p>
All proposed wording is relative to
<a href=http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4861>N4861</a>,
which best corresponds to the C++20 DIS.
</p>

<p>
The intent is that the incubator groups review these proposals by telecon
throughout 2020, indicating which features should be given more attention to
gain implementation experience in time to inform the evolution groups when
face-to-face meetings resume in (hopefully) 2021.  Recommendations will be
tracked in the table below.
</p>

<p>
Checklist for recommendations:
</p>
<table>
  <tr>
    <th>Subclause</th>
    <th>Introduced</th>
    <th>Deprecated</th>
    <th>Paper</th>
    <th>Feature</th>
    <th>Strong Recommendation</th>
    <th>Weak Recommendation</th>
    <th>Incubator Recommendation</th>
    <th>Final Decision</th>
  </tr>

  <tr>
    <td><a href="#3.1">D.1</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1120r0">P1120R0</a></td>
    <td>Arithmetic conversion on enumerations</td>
    <td>No action</td>
    <td>Remove now</td>
    <td>Partial removal</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.2">D.2</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0806r2">P0806R2</a></td>
    <td>Implicit capture of <code>*this</code> by reference</td>
    <td>Remove now</td>
    <td>No action</td>
    <td>No action</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.3">D.3</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1161r3">P1161R3</a></td>
    <td>Comma operator in subscript expressions</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2128r1">P2128R1</a></td>
    <td>Remove now</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.4">D.4</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1120r0">P1120R0</a></td>
    <td>Array comparisons</td>
    <td>Remove now</td>
    <td>No action</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.5">D.5</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1152r4">P1152R4</a></td>
    <td>Deprecated use of <code>volatile</code></td>
    <td>No action</td>
    <td>Remove now</td>
    <td>pending...</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.6">D.6</a></td>
    <td>C++11</td>
    <td>C++17</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0386r2">P0386R2</a></td>
    <td>Reclare <code>constexpr</code> members</td>
    <td>Remove now</td>
    <td>No action</td>
    <td>pending...</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.7">D.7</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1815r2">P1815R2</a></td>
    <td>Non-local use of TU-local entities</td>
    <td>No action</td>
    <td>No action yet</td>
    <td>pending...</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.8">D.8</a></td>
    <td>C++98</td>
    <td>C++11</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3203">N3203</a></td>
    <td>Implicit special members</td>
    <td>Remove on copy<br/>Undeprecate on dtor</td>
    <td>No action yet</td>
    <td>pending...</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.9">D.9</a></td>
    <td>C++98</td>
    <td>C++98</td>
    <td></td>
    <td>C <code>&lt;*.h&gt;</code> headers</td>
    <td>Undeprecate</td>
    <td>Remove now</td>
    <td>New paper</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.10">D.10</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td></td>
    <td><i>Requires:</i> clauses</td>
    <td>Remove now</td>
    <td>No action</td>
    <td>Defer to LWG</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.11">D.11</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0768r1">P0768R1</a></td>
    <td><code>relops</code></td>
    <td>Remove now</td>
    <td>Fix mandates</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.12">D.12</a></td>
    <td>C++98</td>
    <td>C++98</td>
    <td></td>
    <td><code>char *</code> streams</td>
    <td>No action</td>
    <td>No action yet</td>
    <td>No action</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.13">D.13</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0767r1">P0767R1</a></td>
    <td>Deprecated type traits</td>
    <td>Fix mandates</td>
    <td>Remove now</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.14">D.14</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a></td>
    <td><code>volatile tuple</code> API</td>
    <td>No action</td>
    <td>No action</td>
    <td>New paper</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.15">D.15</a></td>
    <td>C++17</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a></td>
    <td><code>volatile variant</code> API</td>
    <td>Remove now</td>
    <td>No action</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.16">D.16</a></td>
    <td>C++98</td>
    <td>C++17</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r0">P0174R2</a></td>
    <td><code>std::iterator</code></td>
    <td>Remove now</td>
    <td>Undeprecate</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.17">D.17</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1252r2">P1252R2</a></td>
    <td><code>move_iterator::operator-&gt;</code></td>
    <td>No action</td>
    <td>Remove now</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.18">D.18</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0718r2">P0718R2</a></td>
    <td>C API to use <code>shared_ptr</code> atomically</td>
    <td>Remove now</td>
    <td>Fix mandates</td>
    <td>SG1</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.19">D.19</a></td>
    <td>C++98</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0966r1">P0966R1</a></td>
    <td><code>basic_string::reserve()</code></td>
    <td>No action</td>
    <td>Remove now</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.20">D.20</a></td>
    <td>C++11</td>
    <td>C++17</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0">P0618R0</a></td>
    <td><code>&lt;codecvt&gt;</code></td>
    <td>Remove now</td>
    <td>No action yet</td>
    <td>Remove now</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.21">D.21</a></td>
    <td>C++11</td>
    <td>C++17</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0">P0618R0</a></td>
    <td><code>wstring_convert</code> et al.</td>
    <td>Remove now</td>
    <td>Fix mandates</td>
    <td>SG16</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.22">D.22</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6">P0482R6</a></td>
    <td>Deprecated locale category facets</td>
    <td>No action</td>
    <td>No action</td>
    <td>SG16</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.23">D.23</a></td>
    <td>C++17</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6">P0482R6</a></td>
    <td><code>filesystem::u8path</code></td>
    <td>Fix mandates</td>
    <td>Remove now</td>
    <td>SG16</td>
    <td>pending...</td>
  </tr>
  <tr>
    <td><a href="#3.24">D.24</a></td>
    <td>C++11</td>
    <td>C++20</td>
    <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0883r2">P0883R2</a></td>
    <td>atomic operations</td>
    <td>No action</td>
    <td>Partially Remove</td>
    <td>SG1</td>
    <td>pending...</td>
  </tr>
 </table>

 <p>
 One sign of the success we have had with previous papers is that roughly
 70% of the subclauses in Annex D were added in the latest C++20 standard,
 and only one feature remains that was deprecated by the C++11 standard.
 Notably, that is the last remaining core feature that was deprecated prior
 to C++20.
 </p>

<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.1">Arithmetic conversion on enumerations [depr.arith.conv.enum]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
Clang 10
</blockquote>

<blockquote class="note">
<b>Warn on emum/float compare:</b>
MSVC 19.22
</blockquote>

<blockquote class="note">
<b>Warn comparing enums:</b>
Clang 3.3 (earliest I could test)
gcc 4.1.2 (earliest I could test)
</blockquote>

<blockquote class="note">
<b>Not tested:</b>
EDG
</blockquote>


<p>
This feature was deprecated as part of the effort to make the new
spaceship operator <i>do the right thing</i>, adopted by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1120r0">P1120R0</a>.
It potentially impacts on code written against C++98 and later standards.
</p>

<p>
With the introduction of the 3-way comparison &quot;spaceship&quot; operator,
there was a concern to avoid some implicit comparisons that might be lossy (due
to rounding of floating point values) or giving up intended type safety (by
using enums rather than integer types to indicate more than just a value).
While the 3-way comparison operator is specified to reject such comparisons,
the existing comparison operators were granted ongoing compatibility in these
cases, but deprecated.  It is likely that most, but not all, such usage relying
on implicit conversion is a latent bug, and all such code would be clearer to
folks reading the code if the implicit conversions were made explicit.  Note
that it is still possible to avoid explicit casts by using the unary
<code>+</code> operator, forcing integral promotion.
</p>

<p>
While we would like to recommend the removal of these deprecated comparisons,
bringing all the comparison operators into harmony for which types they
interoperate on, the case for all uses being latent bugs is not as strong as
for array comparisons (<a href="#3.4">D.4</a>), therefore it seems reasonable
to allow another standard cycle encouraging compilers to issue deprecation
warnings so that users can clean up their code.  Hence, the strong
recommendation is to do nothing for C++23, and strongly reconsider for C++26.
The weak recommendation is to take decisive action and remove now, harmonizing
the comparison operators.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="old_wording">
<h4>7.4 Usual arithmetic conversions [expr.arith.conv]</h4>
<ol>
<li>
Many binary operators that expect operands of arithmetic or enumeration type
cause conversions and yield result types in a similar way. The purpose is to
yield a common type, which is also the type of the result. This pattern is
called the <i>usual arithmetic conversions</i>, which are defined as follows:
  <ol>
  <li>
&mdash; If either operand is of scoped enumeration type (9.7.1), no conversions
are performed; if the other operand does not have the same type, the expression
is ill-formed.
  </li>
  <li><ins>
&mdash; If either operand is of unscoped enumeration type (9.7.1), and the
other operand  is of a different enumeration type or a floating-point type,
the expression is ill-formed.
  </ins></li>
  <li>
&mdash; If either operand is of type <code>long double</code>, the other shall
be converted to <code>long double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>double</code>, the other shall be
converted to <code>double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>float</code>, the other shall be
converted to <code>float</code>.
  </li>
  <li>
&mdash; Otherwise, the integral promotions (7.3.6) shall be performed on both
operands.<sup>56</sup> Then the following rules shall be applied to the
promoted operands:
    <ol>
    <li>
&mdash; If both operands have the same type, no further conversion is needed.
    </li>
    <li>
&mdash; Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer conversion
rank shall be converted to the type of the operand with greater rank.
    </li>
    <li>
&mdash; Otherwise, if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand, the operand
with signed integer type shall be converted to the type of the operand with
unsigned integer type.
    </li>
    <li>
&mdash; Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned integer
type, the operand with unsigned integer type shall be converted to the type of
the operand with signed integer type.
    </li>
    <li>
&mdash; Otherwise, both operands shall be converted to the unsigned integer
type corresponding to the type of the operand with signed integer type.
    </li>
    </ol>
  </li>
  </ol>
</li>
<li><del>
If one operand is of enumeration type and the other operand is of a different
enumeration type or a floating-point type, this behavior is deprecated (D.1).
</del></li>
</ol>

<h4><del>D.1 Arithmetic conversion on enumerations [depr.arith.conv.enum]</del></h4>
<ol>
<li>
<del>The ability to apply the usual arithmetic conversions (7.4) on operands
where one is of enumeration type and the other is of a different enumeration
type or a floating-point type is deprecated. [Note: Three-way comparisons
(7.6.8) between such operands are ill-formed. <i>&mdash;end note</i>]
[<i>Example:</i></del>
<blockquote><pre>
<del>enum E1 { e };</del>
<del>enum E2 { f };</del>
<del>bool b = e &lt;= 3.7;                // deprecated</del>
<del>int k = f - e;                    // deprecated</del>
<del>auto cmp = e &lt;=> f;               // error</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>
</blockquote>

<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/06/09</h4>
<p>
Concerns were raised about ongoing C compatibility.  Any recommendation on
removing deprecated support in D.1 will be forwarded to our WG14 liaison, to
hopefully have a co-ordinated process for removing such features.
</p>
<p>
Concerns were raised over several issues of interoperating with different
enumeration types, including expressions used to initialize global variables,
and for array bounds.  Similarly, metaprogramming idioms from C++98 would often
use enumerations to denote result values (saving on storage for a static data
member), and comparing such named values from different instantiations of the
same template is the expected usage.
</p>
<p>
Another concern was raised for idioms for externally extending another
enumeration without intruding on the original:
</p>
<blockquote><pre>
enum original { e_FIRST, ... , e_LAST };
enum extended { e_NEXT = e_LAST + 1, ... , e_MORE };
</pre></blockquote>
<p>
with the intent that the extended enumeration can interoperate with the
original.
</p>
<p>
There seems fewer concerns for removing the interoperation with floating point
types, although the was some discussion of the workarounds.  There is concern
that the &quot;simple&quot; forced promotion through unary operator
<code>+</code> is too clever/cute, but that <code>static_cast</code>, or
C-style casts, are verbose and risk converting to a different type than the
previous implicit integer promotion.
</p>
<p>
There is an ongoing concern of gaining more specific feedback on implementation
experience with the deprecation warning before making any change, and further
concerns about gaining experience with any removal that might silently change
behavior in SFINAE contexts.
</p>

<h4>Polls:</h4>

<h5>Q1: In C++23 Un-deprecate enum vs. enum?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 1</td><td> 2</td><td> 7</td><td> 6</td><td> 4</td>
</tr>
</table>
<p>No consensus</p>

<h5>Q2: In C++23 Un-deprecate enum vs. floating-point?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 8</td><td> 1</td><td> 4</td><td> 8</td><td> 6</td>
</tr>
</table>
<p>No consensus</p>

<h5>Q3: In C++23 remove the deprecated enum vs. enum facilities?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 1</td><td> 2</td><td>10</td><td> 7</td><td> 1</td>
</tr>
</table>
<p>No consensus</p>


<h5>Q4: In C++23 remove the deprecated enum vs. floating-point facilities?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 7</td><td>10</td><td> 4</td><td> 0</td><td> 1</td>
</tr>
</table>
<p>Progress with this part</p>

<blockquote class="review">
<b>EWGI Review:</b>
Modified weak recommendation (remove just the enum/floating-point behavior)
</blockquote>

<blockquote class="proposed_wording">
<h4>7.4 Usual arithmetic conversions [expr.arith.conv]</h4>
<ol>
<li>
Many binary operators that expect operands of arithmetic or enumeration type
cause conversions and yield result types in a similar way. The purpose is to
yield a common type, which is also the type of the result. This pattern is
called the <i>usual arithmetic conversions</i>, which are defined as follows:
  <ol>
  <li>
&mdash; If either operand is of scoped enumeration type (9.7.1), no conversions
are performed; if the other operand does not have the same type, the expression
is ill-formed.
  </li>
  <li><ins>
&mdash; Otherwise, if either operand is of unscoped enumeration type (9.7.1)
and the other operand is of a floating-point type, the expression is
ill-formed.
  </ins></li>
  <li>
&mdash; <ins>Otherwise,</ins> if either operand is of type <code>long
double</code>, the other shall be converted to <code>long double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>double</code>, the other shall be
converted to <code>double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>float</code>, the other shall be
converted to <code>float</code>.
  </li>
  <li>
&mdash; Otherwise, the integral promotions (7.3.6) shall be performed on both
operands.<sup>56</sup> Then the following rules shall be applied to the
promoted operands:
    <ol>
    <li>
&mdash; If both operands have the same type, no further conversion is needed.
    </li>
    <li>
&mdash; Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer conversion
rank shall be converted to the type of the operand with greater rank.
    </li>
    <li>
&mdash; Otherwise, if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand, the operand
with signed integer type shall be converted to the type of the operand with
unsigned integer type.
    </li>
    <li>
&mdash; Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned integer
type, the operand with unsigned integer type shall be converted to the type of
the operand with signed integer type.
    </li>
    <li>
&mdash; Otherwise, both operands shall be converted to the unsigned integer
type corresponding to the type of the operand with signed integer type.
    </li>
    </ol>
  </li>
  </ol>
</li>
<li>
If <del>one</del><ins>either</ins> operand is of <ins>unscoped</ins>
enumeration type and the other operand is of a different enumeration type
<del>or a floating-point type</del>, this behavior is deprecated (D.1).
</li>
</ol>


<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>


<h4><ins>C.1.X Clause 7: Expressions [diff.cpp20.expr]</ins></h4>
<p><ins>
<b>Affected subclause:</b> 7.4</ins>
<i>Note for editors: [expr.arith.conv]</i>
</p>

<p><ins>
<b>Change:</b> Unscoped enumerations do not implicitly promote to integral type
in expressions with floating point types.
</ins></p>

<p><ins>
<b>Rationale:</b> ...
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 involving both an unscoped
enumeration and a floating point value will be rejected as ill-formed in this
International Standard.  Either argument could be explicitly conerted with a
cast, or the enumeration could be explicitly promoted to an integer with unary
operator +, for no change of meaning since C++ 2020.  [<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>enum multipliers { gigaseconds = 1'000'000 };</ins>
<ins>double century_ish = 3.14 *  gigaseconds;  <i>// ill-formed; previously well-formed</i></ins>
<ins>double century_est = 3.14 * +gigaseconds;  <i>// OK</i></ins>
</pre></blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<h4>C.5.3 Clause 7: expressions [diff.expr]</h4>
<p><ins>
<b>Affected subclause:</b> 7.4</ins>
<i>Note for editors: [expr.arith.conv]</i>
</p>

<p><ins>
<b>Change:</b> Enumerations cannot be used in expressions with floating point
types.
</ins></p>

<p><ins>
<b>Rationale:</b> ...
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of semantically well-defined feature.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Could be automated. Violations will be
diagnosed by the C++ translator. The fix is to add a cast, or explicitly
promote the <code>enum</code> object to an integer with unary operator
<code>+</code>. For example:
</ins></p>
<blockquote><pre>
</pre></blockquote>

<p><ins>
<b>How widely used:</b> Common.
</ins></p>


<h4>D.1 Arithmetic conversion on enumerations [depr.arith.conv.enum]</h4>
<ol>
<li>
The ability to apply the usual arithmetic conversions (7.4) on operands where
one is of <ins>unscoped</ins> enumeration type and the other is of a different
enumeration type <del>or a floating-point type</del> is deprecated. [Note:
Three-way comparisons (7.6.8) between such operands are ill-formed.
<i>&mdash;end note</i>]
[<i>Example:</i>
<blockquote><pre>
enum E1 { e };
enum E2 { f };
<del>bool b = e &lt;= 3.7;                // deprecated</del>
int k = f - e;                    // deprecated
auto cmp = e &lt;=> f;               // error
</pre></blockquote>
<i>&mdash;end example</i>]
</li>
</ol>
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.2">Implicit capture of <code>*this</code> by reference [depr.capture.this]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
EDG 5.1, gcc 9, MSVC 19.22
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
Clang
</blockquote>


<p>
This feature was deprecated in C++20 by
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0806r2">P0806R2</a>.
Its removal would potentially impact on programs written against C++11 or a
later standard.
</p>
<p>
The concern addressed by the paper is that the implicit capture of
<code>this</code> as a <i>reference</i> to data members on a default-capture
that copies is surprising and often misleading.  C++20 introduced the explicit
capture of <code>this</code> as a pointer, or <code>*this</code> by value, to
clearly disambiguate the different use cases.  However, as the syntax to
migrate to was introduced only in C++20, there was a clear desire for at least
one standard retaining the implicit capture support as deprecated while users
migrate their code at a time of their own choosing.
</p>
<p>
In the interest of clear code and fewer bugs from the surprising implicit
defaults, the strong recommendation of this paper is to complete the work
started in P0806 and remove the implicit capture from C++23.  The weak
recommendation is to retain deprecated support for another three years, and
strongly reconsider removal in C++26.  There is no suggestion to undeprecate.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="note">
Draft core wording to enforce the removal (simply removing the deprecation
notice is not enough).
</blockquote>

<blockquote class="old_wording">
<h4><del>D.2 Implicit capture of <code>*this</code> by reference[depr.capture.this]</del></h4>
<ol>
<li>
<del>For compatibility with prior C++ International Standards, a
<i>lambda-expression</i> with <i>capture-default</i> <code>=</code> (7.5.5.2) may
implicitly capture <code>*this</code> by reference. [<i>Example:</i></del>
<blockquote><pre>
<del>struct X {</del>
  <del>int x;</del>
  <del>void foo(int n) {</del>
    <del>auto f = [=]() { x = n; };        // deprecated: x means this-&gt;x, not a copy thereof</del>
    <del>auto g = [=, this]() { x = n; };  // recommended replacement</del>
  <del>}</del>
<del>};</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>
</blockquote>

<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Take no action yet, strongly reconsider removal in C++26.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/06/09</h4>
<p>
Concerns were raised about a lack of user experience with these, and a concern
that the proposed fix for code that removes the deprecated syntax is actually
ill-formed in earlier dialects of the language, prior to C++17.  Removing this
feature may make supporting long-lived code bases that support multiple C++
dialects awkward.
</p>
<p>
There was no enthusiasm to undeprecate the feature without a separate paper.
</p>

<h4>Polls:</h4>

<h5>Q1: In C++23, remove the deprecated implicit capture of *this by reference:</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 2</td><td> 2</td><td> 7</td><td> 6</td><td> 2</td>
</tr>
</table>
<p>No consensus</p>


<blockquote class="review">
<b>EWGI Review:</b>
Take no action for C++23.
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.3">Comma operator in subscript expressions [depr.comma.subscript]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
Clang 9, EDG 6.0, gcc 10, MSVC 19.25
</blockquote>


<blockquote class="note">
A more complete treatment of removing this feature and directly replacing it
with support for multi-index array operators is presented in paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2128r1">P2128R1</a>
to which we might prefer to defer all handling of this topic.
</blockquote>


<p>
This feature was deprecated for C++20 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1161r3">P1161R3</a>
to allow for a future extension in the language to support a simpler syntax for
multiple-dimension arrays.  Its removal would impact on code written against
the C++98 and later standards, and potentially interoperating with C language
headers.
</p>

<p>
There is a question over the value of removing this deprecated feature without
also adding the extension for multiple-dimension arrays, which goes beyond the
scope of this simpler review paper.  The conservative view is that this would
lead to code breakage for no clear benefit,so the strong recommendation is to
do retain this feature as part of the overall review.  The alternative view is
that immediately applying a new meaning to existing syntax as part of an
updated standard is a risk we could avoid by requiring at least one standard to
make such code ill-formed, rather than merely deprecated.  The weak
recommendation is to remove this feature from C++23 to better enable
repurposing the syntax in C++26, or beyond.
</p>

<p>
On as separate note regarding wording, we observe that the convention for
deprecating a feature in the core language is to normatively define the
deprecation in the core clauses (4-15) and then call back to that deprecation
notice from Annex D.  The C++20 standard has this backwards for this particular
deprecation, with the two references to deprecation in the core clauses being
<i>Note:</i>s, and the only normative text being in Annex D.  At least one of
the two <i>Note:</i>s should become normative, if the feature is retained.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Clean up wording.
</blockquote>

<blockquote class="old_wording">	
<h4>7.6.1.1 Subscripting [expr.sub]</h4>
<ol start="2">
<li>
<del>[<i>Note:</i></del> A comma expression (7.6.20) appearing as the
<i>expr-or-braced-init-list</i> of a subscripting expression is deprecated; see
D.3. <del><i>&mdash;end note</i>]</del>
</li>
</ol>

<h4>7.6.20 Comma operator [expr.comma]</h4>
<ol start="3">
<li>
<del>[<i>Note:</i></del> A comma expression (7.6.20) appearing as the
<i>expr-or-braced-init-list</i> of a subscripting expression is deprecated; see
D.3. <del><i>&mdash;end note</i>]</del>
</li>
</ol>
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="proposed_wording">	
<h4>7.6.1.1 Subscripting [expr.sub]</h4>
<ol start="2">
<li><del>[<i>Note:</i></del>
A comma expression (7.6.20) appearing as the <i>expr-or-braced-init-list</i> of
a subscripting expression is <ins>ill-formed.</ins><del>deprecated; see
D.3. <i>&mdash;end note</i>]</del>
</li>
</ol>

<h4>7.6.20 Comma operator [expr.comma]</h4>
<ol start="3">
<li>
[<i>Note:</i> A comma expression (7.6.20) appearing as the
<i>expr-or-braced-init-list</i> of a subscripting expression is <ins>ill-formed</ins><del>deprecated; see
D.3</del>. <i>&mdash;end note</i>]
</li>
</ol>


<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>


<h4><ins>C.1.X Clause 7: Expressions [diff.cpp20.expr]</ins></h4>
<p><ins>
<b>Affected subclause:</b> 7.6.1.1</ins>
<i>Note for editors: [expr.sub]</i>
</p>

<p><ins>
<b>Change:</b> Cannot parse unparenthesized comma expressions as subscript
expressions.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was surprising for users familiar with other
languages.  It was removed to allow a future extension to support overloading
the subscript operator for multiple arguments.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 program using a comma
expression as the argument to a subscript expression will be rejected as
ill-formed in this International Standard.  The intended comma expression can
be enclosed in parentheses for no change of meaning since C++ 2020.
[<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>void f(int *a, int b, int c) {</ins>
   <ins>a[b,c];            <i>// ill-formed; previously well-formed</i></ins>
   <ins>a[(b,c)];          <i>// OK</i></ins>
<ins>}</ins>
</pre></blockquote>
<blockquote class="note">
Add an example of a DSEL
</blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<h4>C.5.3 Clause 7: expressions [diff.expr]</h4>
<p><ins>
<b>Affected subclause:</b> 7.6.1.1
</ins><i>Note for editors: [expr.sub]</i><ins>
</ins></p>

<p><ins>
<b>Change:</b> Cannot parse unparenthesized comma expressions as subscript
expressions.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was surprising for users familiar with other
languages.  It was removed to allow a future extension to support overloading
the subscript operator for multiple arguments.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of semantically well-defined feature.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Could be automated. Violations will be
diagnosed by the C++ translator. The fix is to add parentheses. For example:
</ins></p>
<blockquote><pre>
<ins>void f(int *a, int b, int c) {</ins>
   <ins>a[b,c];            <i>// ill-formed; previously well-formed</i></ins>
   <ins>a[(b,c)];          <i>// OK</i></ins>
<ins>}</ins>
</pre></blockquote>

<p><ins>
<b>How widely used:</b> Rare.
</ins></p>


<h4><del>D.3 Comma operator in subscript expressions [depr.comma.subscript]</del></h4>
<ol>
<li>
<del>A comma expression (7.6.20) appearing as the <i>expr-or-braced-init-list</i>
of a subscripting expression (7.6.1.1) is deprecated. [<i>Note:</i> A
parenthesized comma expression is not deprecated. <i>&mdash;end note</i>]
[<i>Example:</i></del>
<blockquote><pre>
<del>void f(int *a, int b, int c) {</del>
      <del>a[b,c];                     // deprecated</del>
      <del>a[(b,c)];                   // OK</del>
<del>}</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>
</blockquote>


<h4>Initial Review: telecon 2020/06/09</h4>
<p>
Several concerns were raised that might be better addressed for when EWG take a
final decision.  First, there is the existing paper, P2128, that seeks to both
remove this deprecated feature, and replace it with a new meaning.  One option
is to delegate entirely to that paper, but loud concerns were also raised about
changing meaning, and silently changing behavior, in the same standard.  There
is some support for removing the deprecated behavior now, and holding P2128
back until C++26.  From the perspective of this paper, the notion is to proceed
and treat P2128 independently.
</p>
<p>
Concerns were raised about implementation experience.  While it is notable that
all current compiler with C++20 support warn on this deprecation, some of those
compilers are only a month or two old, and we get experience only when folks
compile in the experimental C++20 modes.  While we expect experience to grow,
it is still minimal.  It was also noted that the original paper performed a
survey of popular open source libraries to assess impact, and hit only a
vanishingly small set of matches in a deprecated Boost library:
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1161r3#without-duplication-caused-by-headers-included-multiple-times-throughout-a-project">link</a>
</p>
<p>
A final concern was raised about ongoing C compatibility, which will be
forwarded to our WG14 liaison, to hopefully have a co-ordinated process for
removing this feature.
</p>

<h4>Polls:</h4>

<h5>Q1: In C++23, remove the use of comma operator in subscript expressions?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 8</td><td> 9</td><td> 2</td><td> 1</td><td> 1</td>
</tr>
</table>
<p>Follow up with this direction</p>


<blockquote class="review">
<b>EWGI Review:</b>
Accept the weak recommendation.
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.4">Array comparisons [depr.array.comp]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
Clang 10, MSVC 19.22
</blockquote>

<blockquote class="note">
<b>QoI Warning</b>
Clang 3.3 (earliest I could test)
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
gcc
</blockquote>

<blockquote class="note">
<b>Not tested:</b>
EDG
</blockquote>


<p>
This feature was deprecated as part of the effort to make the new spaceship
operator <i>do the right thing</i>, adopted by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1120r0">P1120R0</a>.
It potentially impacts on code written against C++98 and later standards.
</p>

<p>
The deprecated comparison operator for arrays was not so much a deliberately
designed feature, but accidental oversight that array-to-pointer decay would
kick in, and so we compare whether two arrays are literally the same array at
the same address, rather than whether two distinct arrays have the same
contents.  Identity tests are typically performed by explicitly taking the
address of the objects we wish to validate; it would be highly unusual to rely
on an implicit pointer decay to perform that task.  The trick, if performed
intentionally, offers no efficiency gain over explicitly taking the address of
the array, but would fool a large number of subsequent code readers and
reviewers who are not familiar with this trick.  We do note that function
comparison performs exactly the same decay, and users are not surprised that
comparing functions is an identity test.
</p>

<p>
Given the likelihood that any usage of this comparison operator is a bug
waiting to be detected, this could be a real concern for software reliability.
Therefore, the strong recommendation is to remove this feature immediately from
C++23.  However, note for wording, that the comparison of an array with a
pointer value is <i>not</i> deprecated in C++20, is reasonably idiomatic for
practitioners of C++, and is intended to continue to be supported.  This mimics
the behavior of the spaceship operator.
</p>

<p>
Given the feature was so recently deprecated, the weak recommendation is to sit
on the feature for another 3 years giving users more time to find (presumably
benign) uses in their code and correct at a time of their choosing.  We would
expect to strongly recommend the removal again in another three years though,
rather than consider undeprecation for such a feature.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="proposed_wording">
<h4>7.6.9 Relational operators [expr.rel]</h4>
<ol>
<li>
The relational operators group left-to-right. [<i>Example:</i>
<code>a&lt;b&lt;c</code> means <code>(a&lt;b)&lt;c</code> and not
<code>(a&lt;b)&amp;&amp;(b&lt;c)</code>. <i>&mdash; end example</i>]
<blockquote><pre><i>
relational-expression :
    compare-expression
    relational-expression &lt; compare-expression
    relational-expression &gt; compare-expression
    relational-expression &lt;= compare-expression
    relational-expression &gt;= compare-expression
</i></pre></blockquote>
The lvalue-to-rvalue (7.3.1)<del>, array-to-pointer (7.3.2),</del> and
function-to-pointer(7.3.3) standard conversions are performed on the operands.
<ins>
If at least one of the operands is a pointer, array-to-pointer conversions
(7.3.2) are performed.
</ins>
<del>
The comparison is deprecated if both operands were of array type prior to these
conversions (D.4).
</del>
</li>
<li>
The converted operands shall have arithmetic, enumeration, or pointer type.
The operators <code>&lt;</code> (less than), <code>&gt;</code> (greater than),
<code>&lt;=</code> (less than or equal to), and <code>&gt;=</code> (greater
than or equal to) all yield <code>false</code> or <code>true</code>. The type
of the result is <code>bool</code>.
</li>
<li>
The usual arithmetic conversions (7.4) are performed on operands of arithmetic
or enumeration type. If both operands are pointers, pointer conversions
(7.3.11) and qualification conversions (7.3.5) are performed to bring them to
their composite pointer type (7.2.2). After conversions, the operands shall
have the same type.
</li>
<li>
The result of comparing unequal pointers to objects ...
</li>
</ol>

<h4>7.6.10 Equality operators [expr.eq]</h4>
<blockquote><pre><i>
equality-expression :
    relational-expression
    equality-expression == relational-expression
    equality-expression != relational-expression
</i></pre></blockquote>

<ol>
<li>
The <code>==</code> (equal to) and the <code>!=</code> (not equal to) operators
group left-to-right. The lvalue-to-rvalue (7.3.1)<del>, array-to-pointer
(7.3.2),</del> and function-to-pointer (7.3.3) standard conversions are
performed on the operands.
<del>
The comparison is deprecated if both operands
were of array type prior to these conversions (D.4).
</del>
</li>
<li>
If at least one of the operands is a pointer, <ins>array-to-pointer
conversions (7.3.2),</ins> pointer conversions (7.3.11), function
pointer conversions (7.3.13), and qualification conversions (7.3.5)
are performed on both operands to bring them to their composite
pointer type (7.2.2).
<del>
Comparing pointers is defined as follows:
</del>
</li>
<li>
The converted operands shall have arithmetic, enumeration, pointer,
or pointer-to-member type, or type <code>std::nullptr_t</code>. The
operators <code>==</code> and <code>!=</code> both yield <code>true</code> or
<code>false</code>, i.e., a result of type <code>bool</code>.  In each case
below, the operands shall have the same type after the specified
conversions have been applied.
</li>
<li>
<ins>
Comparing pointers is defined as follows:
</ins>
  <ol>
  <li>
  &mdash; If one pointer represents the address of a complete object,
  and another pointer represents the address one past the last element
  of a different complete object,<sup>79</sup> the result of the comparison is
  unspecified.
</li>
<li>
  &mdash; Otherwise, if the pointers are both null, both point to the
  same function, or both represent the same address (6.8.2), they
  compare equal.
</li>
<li>
  &mdash; Otherwise, the pointers compare unequal.
</li>
  </ol>
</li>
<li>
If at least one of the operands is a pointer to member, ...
</li>
</ol>


<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>


<h4><ins>C.1.X Clause 7: Expressions [diff.cpp20.expr]</ins></h4>
<p><ins>
<b>Affected subclause:</b> 7.6.9 and 7.6.10</ins>
<i>Note for editors: [expr.rel] and [expr.eq]</i>
</p>

<p><ins>
<b>Change:</b> Cannot compare two objects of array type.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was confusing, as it did not compare the
contents of the two arrays, but compare their addresses.  Depending on context,
this would either report whether the two arrays were the same object, or have
an unspecified result.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 program directly comparing
two array objects will be rejected as ill-formed in this International
Standard. [<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>int arr1[5];</ins>
<ins>int arr2[5];</ins>
<ins>bool same = arr1 ==  arr2;       <i>// ill-formed; previously well-formed</i></ins>
<ins>bool idem = arr1 == +arr2;       <i>// compare addresses, unspecified result</i></ins>
</pre></blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<h4>C.5.3 Clause 7: expressions [diff.expr]</h4>
<p><ins>
<b>Affected subclause:</b> 7.6.9 and 7.6.10</ins>
<i>Note for editors: [expr.rel] and [expr.eq]</i>
</p>

<p><ins>
<b>Change:</b> Cannot compare two objects of array type.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was confusing, as it did not compare the
contents of the two arrays, but compare their addresses.  Depending on context,
this would either report whether the two arrays were the same object, or have
an unspecified result.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of feature with unspecified behavior.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Violations will be diagnosed by the C++
translator.
</ins></p>

<p><ins>
<b>How widely used:</b> Rare. In the cases where the result is well defined,
it is reporting whether both arguments are the same object, using the same
name.
</ins></p>


<h4><del>D.4 Array comparisons [depr.array.comp]</del></h4>
<ol>
<li>
<del>Equality and relational comparisons (7.6.10, 7.6.9) between two operands
of array type are deprecated. [<i>Note:</i> Three-way comparisons (7.6.8)
between such operands are ill-formed. <i>&mdash;end note</i>]
[<i>Example:</i></del>
<blockquote><pre>
<del>int arr1[5];</del>
<del>int arr2[5];</del>
<del>bool same = arr1 == arr2;       // deprecated, same as &amp;arr1[0] == &amp;arr2[0],</del>
                                <del>// does not compare array contents</del>
<del>auto cmp = arr1 &lt;=&gt; arr2;       // error</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/06/09</h4>
<p>
It was noted that comparison of pointer values is often unspecified, rather
than well-defined, unless both arrays happen to be members of the same class,
or are both elements of the same multi-dimensional array.
</p>
<p>
General agreement that this is a good opportunity to remove a landmine from the
language that offers little benefit, even when correctly used as intended.
</p>
<p>
A concern was raised about ongoing C compatibility, which will be forwarded to
our WG14 liaison, to hopefully have a co-ordinated process for removing this
feature.
</p>

<h4>Polls:</h4>

<h5>Q1: In C++23, remove the deprecated use of array comparisons?</h5>
<table class="poll">
<tr>
  <td>SF</td><td> F</td><td> N</td><td> A</td><td>SA</td>
</tr>
<tr>
  <td> 9</td><td> 9</td><td> 3</td><td> 0</td><td> 0</td>
</tr>
</table>
<p>Follow up with this direction</p>


<blockquote class="review">
<b>EWGI Review:</b>
Accept the strong recommendation.
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.5">Deprecated volatile types [depr.volatile.type]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
Clang 10, EDG 6.0, gcc 10
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
MSVC
</blockquote>


<p>
The <code>volatile</code> keyword is an original part of the C legacy for C++,
and describes constraints on programs intended to model hardware changing
values beyond the program's control.  As this entered the type system of
C++, certain interactions were discovered to be troublesome, and latent
bugs that could be detected at the time of program translation go unreported.
The paper

breaks down each context where the <code>volatile</code> keyword can be used,
and deprecated those uses that are unconditionally dangerous, or serve no
good purpose.  This paper is the first opportunity to go further, and
remove those use cases after 3 years of giving users deprecation warnings.
</p>

<p>
A quick micro-analysis suggests the main concerns of the first two paragraphs
are read/modify/write operations, where by the nature of volatile objects, the
value being rewritten may have changed since read and modified.  This kind of
pattern is most likely in old (pre-C++11) code using <code>volatile</code> as a
poor proxy for atomic.  Since we will have over a decade of real atomic support
in the language when C++23 ships, it could be desirable to further encourage
such code (when compiled in the latest dialect) to adapt to the memory model
and its stronger guarantees.
</p>

<p>
The third paragraph addresses function arguments and return values.  These are
temporary or elided objects created entirely by the compiler, and guaranteed to
not display the uncertainty of value implied by the <code>volatile</code>
keyword.  As such, any use is redundant and misleading, so it would be helpful
to remove this facility sooner rather than later, and have one fewer oddity to
teach when learning (and understanding) the language.  The biggest concern
would be for compatibility with C code, that may still use this feature in its
headers.  To mitigate, me may consider removing <code>volatile</code> function
parameters and return values for only functions with
<code>extern &quot;C++&quot;</code> linkage.
</p>

<p>
The fourth paragraph considers volatile qualifier in structured bindings, and
can affect only code written since C++17, that will have been deprecated as
long as it was non-deprecated when C++23 is published.  It would be good to
remove this now, before more deprecated code is written.
</p>

<p>
As outright removal is introducing potential breakage into programs that have
been compiling successfully since C++98, this paper strongly recommends to hold
this feature in Annex D as deprecated for another 3 years, and strongly
consider taking further action for C++26.  However, as there is the potential
to diagnose real bugs for users to fix, the weak recommendation is to remove
these deprecated use cases immediately from C++23.  It would also be possible
to review each of the 4 noted usages separately, and remove only the features
with lowest risk from removal, notably paragraphs 3 and 4.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="note">
Note that the core terms <i>arithmetic type</i> and <i>pointer type</i> refer
only to cv-unqualified types, and cv-qualifiers are incorporated only for the
larger classification of <i>scalar types</i>; therefore, much of the deprecated
wording in clause 7 is already redundant - this will be core issue 2448.  In
principle, we need to add words to enable the feature that C++20 intended to
deprecate!  The wording issue goes back to C++98 though, as current
implementations provide the intended deprecated behavior, not a literal
interpretation of the standard.
</blockquote>

<blockquote class="draft_wording">

<h4>7.6.1.5 Increment and decrement [expr.post.incr]</h4>
<ol>
<li>
The value of a postfix <code>++</code> expression is the value of its operand.
[<i>Note:</i> The value obtained is a copy of the original value. <i>&mdash;end
note</i>] The operand shall be a modifiable lvalue. The type of the operand
shall be an arithmetic type other than <del><i>cv</i></del> <code>bool</code>,
or a pointer to a complete object type. <del>An operand with volatile-qualified
type is deprecated; see D.5.</del> The value of ...
</li>
</ol>

<h4>7.6.2.2 Increment and decrement [expr.pre.incr]</h4>
<ol>
<li>
The operand of prefix <code>++</code> is modified (3.1) by adding
<code>1</code>. The operand shall be a modifiable lvalue. The type of the
operand shall be an arithmetic type other than <del><i>cv</i></del>
<code>bool</code>, or a pointer to a completely-defined object type. <del>An
operand with volatile-qualified type is deprecated; see D.5.</del> The result
is ...
</li>
</ol>

<h4>7.6.19 Assignment and compound assignment operators [expr.ass]</h4>
<ol start="5">
<li>
<del>A simple assignment whose left operand is of a
<code>volatile</code>-qualified type is deprecated (D.5) unless the (possibly
parenthesized) assignment is a discarded-value expression or an unevaluated
operand.</del>
<blockquote class="note">
Draft a replacement paragraph so that assignment to <code>volatile</code>-qualified
types remains valid, but only through discarded-value expressions.  If not an
ABI consideration, could we make the built-in assignment operators for
<code>volatile</code>-qualified types return <code>void</code>?
</blockquote>
</li>

<li>
The behavior of an expression of the form <code>E1</code> <i>op</i><code>=
E2</code> is equivalent to <code>E1 = E1</code> <i>op</i> <code>E2</code>
except that <code>E1</code> is evaluated only once. <del>Such expressions are
deprecated if <code>E1</code> has <code>volatile</code>-qualified type; see
D.5.</del> For <code>+=</code> and <code>-=</code>, <code>E1</code> shall
either have arithmetic type or be a pointer to a possibly cv-qualified
completely-defined object type. In all other cases, <code>E1</code> shall have
arithmetic type.
</li>
</ol>


<h4>9.3.3.5 Functions [dcl.fct]</h4>
<blockquote class="note">
It is expected that removing support for volatile-qualified function parameters
will have ripples more widely through the standard, and that potentially
cv-qualified types may become potentially const-qualified types in a number of
places, after a deeper audit.
</blockquote>

<ol start="4">
<li>
The <i>parameter-declaration-clause</i> determines the arguments that can be
specified, and their processing, when the function is called. [<i>Note:</i> The
<i>parameter-declaration-clause</i> is used to convert the arguments specified
on the function call; see 7.6.1.2. <i>&mdash;end note</i>] If the
<i>parameter-declaration-clause</i> is empty, the function takes no arguments.
A parameter list consisting of a single unnamed parameter of non-dependent type
<code>void</code> is equivalent to an empty parameter list. Except for this
special case, a parameter shall not have type <i>cv</i> <code>void</code>. A
parameter <del>with</del><ins>shall not have a</ins> volatile-qualified type
<del>is deprecated; see D.5</del>. If the <i>parameter-declaration-clause</i>
terminates with an ellipsis or a function parameter pack (13.7.3), the number
of arguments shall be equal to or greater than the number of parameters that do
not have a default argument and are not function parameter packs. Where
syntactically correct and where “...” is not part of an
<i>abstract-declarator</i>, “, ...” is synonymous with “...”.
[<i>Example:</i> The declaration
<pre>
     int printf(const char*, ...);
</pre>
declares a function that can be called with varying numbers and types of
arguments.
<pre>
     printf("hello world");
     printf("a=%d b=%d", a, b);
</pre>
However, the first argument must be of a type that can be converted to a
<code>const char*</code>. <i>&mdash;end example</i>] [<i>Note:</i> The standard header <code>&lt;cstdarg&gt;</code> (17.13.1) contains a
mechanism for accessing arguments passed using the ellipsis (see 7.6.1.2 and
17.13). <i>&mdash;end note</i>]
</li>
</ol>

<ol start="12">
<li>
<del>A volatile-qualified return type is deprecated; see D.5.</del>
<ins>A return type shall not be volatile-qualified. [<i>Note:</i> References to
volatile-qualified types are permitted, as reference types do not have a top
level cv-qualifier. <i>&mdash;end note</i>]</ins>
</li>
</ol>


<h4>9.6 Structured binding declarations [dcl.struct.bind]</h4>
<blockquote class="note">
As a reminder, the grammar for a structured binding is the following
<i>simple-declaration</i>:
<pre>
<i>attribute-specifier-seq<sub>opt</sub> decl-specifier-seq ref-qualifier<sub>opt</sub> </i>[<i> identifier-list </i>]<i> initializer </i>;
</pre>
</blockquote>

<ol>
<li>
A structured binding declaration introduces the identifiers
<code>v<sub>0</sub></code>, <code>v<sub>1</sub></code>,
<code>v<sub>2</sub></code>, . . .  of the <i>identifier-list</i> as names
(6.4.1) of structured bindings. Let <i>cv</i> denote the <i>cv-qualifiers</i>
in the <i>decl-specifier-seq</i> and <i>S</i> consist of the
<i>storage-class-specifiers</i> of the <i>decl-specifier-seq</i> (if any). A
<i>cv</i> that includes <code>volatile</code> is deprecated; see D.5. First, a
variable with a unique name <code>e</code> is introduced. If the
<i>assignment-expression</i> in the <i>initializer</i> has array type
<code>A</code> and no <i>ref-qualifier</i> is present, <code>e</code> is
defined by
<blockquote>
<i>attribute-specifier-seq<sub>opt</sub></i> <i>S</i> <code><i>cv</i> A e ;</code>
</blockquote>
and each element is copy-initialized or direct-initialized from the
corresponding element of the <i>assignment-expression</i> as specified by the
form of the <i>initializer</i>. Otherwise, <code>e</code> is defined as-if by
<blockquote>
<i>attribute-specifier-seq<sub>opt</sub> decl-specifier-seq ref-qualifier<sub>opt</sub></i> <code>e</code> <i>initializer</i> <code>;</code>
</blockquote>
where the declaration is never interpreted as a function declaration and the
parts of the declaration other than the <i>declarator-id</i> are taken from the
corresponding structured binding declaration. The type of the
<i>id-expression</i> <code>e</code> is called <code>E</code>. [<i>Note:</i>
<code>E</code> is never a reference type (7.2). <i>&mdash;end note</i>]

<blockquote class="note">
Ideally, this whole paragraph should be rewritten to avoid introducing a
<i>cv</i> that can never include the <code>volatile</code> qualifier.
</blockquote>
</li>

<li>
If the <i>initializer</i> refers to one of the names introduced by the structured
binding declaration, the program is ill-formed.
</li>

<li>
If <code>E</code> is an array type with element type <code>T</code>, the number of elements in the
<i>identifier-list</i> shall be equal to the number of elements of <code>E</code>. Each
<code>v<sub>i</sub></code> is the name of an lvalue that refers to the element <i>i</i> of the
array and whose type is <code>T</code>; the referenced type is <code>T</code>. [<i>Note:</i> The
top-level cv-qualifiers of <code>T</code> are <i>cv</i>. <i>&mdash;end note</i>]
[<i>Example:</i>
<blockquote><pre>
auto f() -> int(&amp;)[2];
auto [ x, y ] = f();    <i>// x and y refer to elements in a copy of the array return value</i>
auto&amp; [ xr, yr ] = f(); <i>// xr and yr refer to elements in the array referred to by f's return value</i>
</pre></blockquote>
<i>&mdash;end example</i>]
</li>

<li>
Otherwise, if the <i>qualified-id</i> <code>std::tuple_size&lt;E&gt;</code>
names a complete class type with a member named <code>value</code>, the
expression <code>std::tuple_size&lt;E&gt;::value</code> shall be a well-formed
integral constant expression and the number of elements in the
<i>identifier-list</i> shall be equal to the value of that expression. Let
<code>i</code> be an index prvalue of type <code>std::size_t</code>
corresponding to <code>v<sub>i</sub></code>. The <i>unqualified-id</i>
<code>get</code> is looked up in the scope of <code>E</code> by class member
access lookup (6.5.5), and if that finds at least one declaration that is a
function template whose first template parameter is a non-type parameter, the
<i>initializer</i> is <code>e.get&lt;i&gt;()</code>.  Otherwise, the
<i>initializer</i> is <code>get&lt;i&gt;(e)</code>, where <code>get</code> is
looked up in the associated namespaces (6.5.2). In either case,
<code>get&lt;i&gt;</code> is interpreted as a <i>template-id</i>. [<i>Note:</i>
Ordinary unqualified lookup (6.5.1) is not performed. <i>&mdash;end note</i>]
In either case, <code>e</code> is an lvalue if the type of the entity
<code>e</code> is an lvalue reference and an xvalue otherwise. Given the type
<code>T<sub>i</sub></code> designated by <code>std::tuple_element&lt;i,
E&gt;::type</code> and the type <code>U<sub>i</sub></code> designated by either
<code>T<sub>i</sub>&amp;</code> or <code>T<sub>i</sub>&amp;&amp;</code>, where
<code>U<sub>i</sub></code> is an lvalue reference if the initializer is an
lvalue and an rvalue reference otherwise, variables are introduced with unique
names <code>r<sub>i</sub></code> as follows:
<blockquote>
<i>S</i> <code>U<sub>i</sub> r<sub>i</sub> =</code> <i>initializer</i> <code>;</code>
</blockquote>
Each v<sub>i</sub> is the name of an lvalue of type <code>T<sub>i</sub></code>
that refers to the object bound to <code>r<sub>i</sub></code>; the referenced
type is <code>T<sub>i</sub></code>.
</li>

<li>
Otherwise, all of <code>E</code>'s non-static data members shall be direct
members of E or of the same base class of <code>E</code>, well-formed when
named as <code>e.name</code> in the context of the structured binding,
<code>E</code> shall not have an anonymous union member, and the number of
elements in the <i>identifier-list</i> shall be equal to the number of
non-static data members of <code>E</code>. Designating the non-static data
members of E as <code>m<sub>0</sub></code>, <code>m<sub>1</sub></code>,
<code>m<sub>2</sub></code>, . . . (in declaration order), each
<code>v<sub>i</sub></code> is the name of an lvalue that refers to the member
<code>m<sub>i</sub></code> of <code>e</code> and whose type is <i>cv</i>
<code>T<sub>i</sub></code>, where <code>T<sub>i</sub></code> is the declared
type of that member; the referenced type is <i>cv</i>
<code>T<sub>i</sub></code>.  The lvalue is a bit-field if that member is a
bit-field. [<i>Example:</i>
<blockquote><pre>
struct S { int x1 : 2; volatile double y1; };
S f();
const auto [ x, y ] = f();
</pre></blockquote>
The type of the <i>id-expression</i> <code>x</code> is &quot;<code>const
int</code>&quot;, the type of the <i>id-expression</i> <code>y</code> is
&quot;<code>const volatile double</code>&quot;. <i>&mdash;end example</i>]

<blockquote class="note">
Note that the use of <code>volatile</code> in this example remains valid for
structured bindings, even after the removal of the deprecated parts.
</blockquote>
</li>
</ol>




<h4>12.7 Built-in operators [over.built]</h4>
<ol start="3">
<li><del>
In the remainder of this subclause, <i>vq</i> represents either
<code>volatile</code> or no cv-qualifier.
</del></li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>), where <code>T</code> is an</del>
arithmetic type other than <code>bool</code>, there exist candidate operator
functions of the form
<pre>
<del><i>vq</i></del> T &amp; operator++(<del><i>vq</i></del> T &amp;);
 T operator++(<del><i>vq</i></del> T &amp;, int);
</pre>
</li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>), where <code>T</code> is an</del>
arithmetic type other than <code>bool</code>, there exist candidate operator
functions of the form
<pre>
<del><i>vq</i></del> T &amp; operator--(<del><i>vq</i></del> T &amp;);
 T operator--(<del><i>vq</i></del> T &amp;, int);
</pre>
</li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>)</del><ins>type
<code>T</code></ins>, where <code>T</code> is a cv-qualified or cv-unqualified
object type, there exist candidate operator functions of the form
<pre>
T*<del><i>vq</i></del>&amp; operator++(T*<del><i>vq</i></del>&amp;);
T*<del><i>vq</i></del>&amp; operator--(T*<del><i>vq</i></del>&amp;);
T* operator++(T*<del><i>vq</i></del>&amp;, int);
T* operator--(T*<del><i>vq</i></del>&amp;, int);
</pre>
</li>
</ol>

<ol start="21">
<li>
For every <del>triple (<code>L</code>, <i>vq</i>,
<code>R</code>)</del><ins>pair (<code>L</code>, <code>R</code>)</ins>, where
<code>L</code> is an arithmetic type, and <code>R</code> is a floating-point or
promoted integral type, there exist candidate operator functions of the form
<pre>
<del><i>vq</i></del> L &amp; operator=(<del><i>vq</i></del> L &amp;, R);
<ins>void operator=(volatile L &amp;, R);</ins>

<del><i>vq</i></del> L &amp; operator*=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator/=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator+=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator-=(<del><i>vq</i></del> L &amp;, R);
</pre></li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>)</del><ins>type
<code>T</code></ins>, there exist candidate operator functions of the form
<pre>
T*<del><i>vq</i></del>&amp; operator=(T*<del><i>vq</i></del>&amp;, T*);
<ins>void operator=(T* volatile &amp;, T*);</ins>
</pre>
</li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>), where <code>T</code> is
an</del> enumeration or pointer-to-member type, there exist candidate operator
functions of the form
<pre>
<del><i>vq</i></del> T &amp; operator=(<del><i>vq</i></del> T &amp;, T);
<ins>void operator=(volatile T &amp;, T);</ins>
</pre>
</li>
<li>
For every <del>pair (<code>T</code>, <i>vq</i>)</del><ins>type
<code>T</code></ins>, where <code>T</code> is a cv-qualified or cv-unqualified
object type, there exist candidate operator functions of the form
<pre>
T*<del><i>vq</i></del>&amp; operator+=(T*<del><i>vq</i></del>&amp;, std::ptrdiff_t);
T*<del><i>vq</i></del>&amp; operator-=(T*<del><i>vq</i></del>&amp;, std::ptrdiff_t);
</pre>
</li>
<li>
For every <del>triple (<code>L</code>, <i>vq</i>,
<code>R</code>)</del><ins>pair (<code>L</code>, <code>R</code>)</ins>, where
<code>L</code> is an integral type, and <code>R</code> is a promoted integral
type, there exist candidate operator functions of the form
<pre>
<del><i>vq</i></del> L &amp; operator%=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator&lt;&lt;=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator&gt;&gt;=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator&amp;=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator^=(<del><i>vq</i></del> L &amp;, R);
<del><i>vq</i></del> L &amp; operator|=(<del><i>vq</i></del> L &amp;, R);
</pre>
</li>
</ol>

<h4><del>D.5 Deprecated volatile types [depr.volatile.type]</del></h4>
<ol>
<li>
<del>Postfix <code>++</code> and <code>--</code> expressions (7.6.1.5) and
prefix <code>++</code> and <code>--</code> expressions (7.6.2.2) of
<code>volatile</code>-qualified arithmetic and pointer types are deprecated.</del>
<pre>
<del>[<i>Example:</i></del>
  <del>volatile int velociraptor;</del>
  <del>++velociraptor;                     <i>// deprecated</i></del>
<del><i>&mdash;end example</i>]</del>
</pre>
</li>

<li>
<del>Certain assignments where the left operand is a
<code>volatile</code>-qualified non-class type are deprecated; see 7.6.19.
</del>
<pre>
<del>[<i>Example:</i></del>
  <del>int neck, tail;</del>
  <del>volatile int brachiosaur;</del>
  <del>brachiosaur = neck;                 <i>// OK</i></del>
  <del>tail = brachiosaur;                 <i>// OK</i></del>
  <del>tail = brachiosaur = neck;          <i>// deprecated</i></del>
  <del>brachiosaur += neck;                <i>// deprecated</i></del>
  <del>brachiosaur = brachiosaur + neck;   <i>// OK</i></del>
<del><i>&mdash;end example</i>]</del>
</pre>
</li>

<li>
<del>A function type (9.3.3.5) with a parameter with
<code>volatile</code>-qualified type or with a <code>volatile</code>-qualified
return type is deprecated.</del>
<pre>
<del>[<i>Example:</i></del>
  <del>volatile struct amber jurassic();                              <i>// deprecated</i></del>
  <del>void trex(volatile short left_arm, volatile short right_arm);  <i>// deprecated</i></del>
  <del>void fly(volatile struct pterosaur* pteranodon);               <i>// OK</i></del>
<del><i>&mdash;end example</i>]</del>
</pre>
</li>

<li>
<del>A structured binding (9.6) of a <code>volatile</code>-qualified type is
deprecated.</del>
<pre>
<del>[<i>Example:</i></del>
  <del>struct linhenykus { short forelimb; };</del>
  <del>void park(linhenykus alvarezsauroid) {</del>
    <del>volatile auto [what_is_this] = alvarezsauroid;               <i>// deprecated</i></del>
    <del>// ...</del>
  <del>}</del>
<del><i>&mdash;end example</i>]</del>
</pre>
</li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="review">
<b>EWGI Review:</b>
To be determined...
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.6">Redeclaration of static constexpr data members [depr.static.constexpr]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++17
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
<i>(none)</i>
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
Clang EDG gcc MSVC
</blockquote>


<p>
Static constexpr data members were added to the language in C++11, as part of
the initial constexpr feature.  However, they still required a definition of
the member outside the class.  When inline variables were added in C++17
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0386r2">P0386R2</a>)
then static constexpr data members became implicitly inline, and the external
definition became redundant, so was deprecated.
</p>
<p>
When we considered this feature for removal in C++20, it was thought the change
was too recent for users to have time to adjust, and recommended we reconsider
removal in C++23 (or later).  By the time we publish C++23, this feature will
have been deprecated for exactly as long as it was non-deprecated, 6 years.
The suggested fix to make code confirming again is simple: remove the offending
definition as it is redundant; no other changes are necessary.  For code that
wishes to be compatible across a range of standard dialects, the definition can
be guarded by the preprocessor:
</p>
<pre>
#if __cplusplus &lt; 201703
constexpr Type Class::Member;
#endif
</pre>
<p>
If we were to remove this feature early in the C++23 cycle, and compiler
vendors expose this through their experimental C++23 support, we would get
sufficient feedback if removal of this feature were a step too far, too soon.
The strong recommendation is to remove this feature from C++23.  Note, however,
that at the time of publishing this paper, no current compiler warns of this
deprecation, in either C++17 or C++20 build modes.
</p>
<p>
The feature seems relatively small and harmless; it is not clear that there is
a huge advantage to removing it immediately from C++23, although it would be
one less corner case to teach.  The weak recommendation is to retain this
feature, advocating removal in C++26, by which time the community will have
had most of a decade to clean up old C++11/14 code.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
remove this facility from C++23.
</blockquote>

<blockquote class="draft_wording">
<h4>6.1 Declarations and definitions [basic.def]</h4>
<ol start="2">
<li>
A declaration is a <i>definition</i> unless
  <ol>
<li>&mdash; it declares a function without specifying the function's body (11.4),</li>
<li>&mdash;
it contains the <code>extern</code> specifier (9.2.1) or a
<i>linkage-specification</i><sup>22</sup> (9.11) and neither an
<i>initializer</i> nor a <i>function-body</i>,
</li>
<li>&mdash; it declares a
non-inline static data member in a class definition (11.4, 11.4.8),
</li>
<li><del>&mdash;
it declares a static data member outside a class definition and the variable
was defined within the class with the <code>constexpr</code> specifier (this
usage is deprecated; see D.6),
</del></li>
<li>&mdash; it is introduced by an <i>elaborated-type-specifier</i> (11.3),</li>
<li>&mdash; it is an <i>opaque-enum-declaration</i> (9.7.1),</li>
<li>&mdash; it is a <i>template-parameter</i> (13.2),</li>
<li>&mdash; it is a <i>parameter-declaration</i> (9.3.3.5) in a function declarator that is not the <i>declarator</i> of a <i>function-definition</i>,</li>
<li>&mdash; it is a <code>typedef</code> declaration (9.2.3),</li>
<li>&mdash; it is an <i>alias-declaration</i> (9.2.3),</li>
<li>&mdash; it is a <i>using-declaration</i> (9.9),</li>
<li>&mdash; it is a <i>deduction-guide</i> (13.7.1.2),</li>
<li>&mdash; it is a <i>static_assert-declaration</i> ((9.1),</li>
<li>&mdash; it is an <i>attribute-declaration</i> ((9.1),</li>
<li>&mdash; it is an <i>empty-declaration</i> (9.1),</li>
<li>&mdash; it is a <i>using-directive</i> (9.8.3),</li>

<li>&mdash; it is a <i>using-enum-declaration</i> (9.7.2),</li>
<li>&mdash;
it is a <i>template-declaration</i> (13.1) whose <i>template-head</i> is not
followed by either a <i>concept-definition</i> or a declaration that defines a
function, a class, a variable, or a static data member.
</li>

<li>&mdash; it is an explicit instantiation declaration (13.9.2), or</li>
<li>&mdash; it is an explicit specialization (13.9.3) whose <i>declaration</i> is not a definition.</li>
  </ol>
</li>
</ol>

<h4>11.4.8.2 Static data members [class.static.data]</h4>
<ol start="4">
<li>
If a non-volatile non-inline <code>const</code> static data member is of
integral or enumeration type, its declaration in the class definition can
specify a <i>brace-or-equal-initializer</i> in which every
<i>initializer-clause</i> that is an <i>assignment-expression</i> is a constant
expression (7.7). The member shall still be defined in a namespace scope if it
is odr-used (6.3) in the program and the namespace scope definition shall not
contain an <i>initializer</i>. An inline static data member may be defined in
the class definition and may specify a <i>brace-or-equal-initializer</i>.
<del>If the member is declared with the <code>constexpr</code> specifier, it
may be redeclared in namespace scope with no initializer (this usage is
deprecated; see D.6).</del> Declarations of other static data members shall not
specify a <i>brace-or-equal-initializer</i>.
</li>
</ol>

<h4><del>D.6 Redeclaration of static constexpr data members [depr.static.constexpr]</del></h4>
<ol>
<li><del>
For compatibility with prior C++ International Standards, a
<code>constexpr</code> static data member may be redundantly redeclared outside
the class with no initializer. This usage is deprecated. [ <i>Example:</i>
<blockquote><pre>
<del>struct A {</del>
  <del>static constexpr int n = 5; <i>// definition (declaration in C++ 2014)</i></del>
<del>};</del>

<del>constexpr int A::n;           <i>// redundant declaration (definition in C++ 2014)</i></del>
</pre></blockquote>
&mdash; <i>end example</i> ]
</del></li>
</ol>
</blockquote>

<blockquote class="note">
No impact on library wording is anticipated by this removal.
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Take no action yet, consider again for C++26.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="review">
<b>EWGI Review:</b>
To be determined...
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.7">Non-local use of TU-local entities [depr.local]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
<i>(none)</i>
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
Clang EDG gcc MSVC
</blockquote>

<p>
This feature was deprecated as part of the effort to cleanly introduce modules
into the language, and was adopted by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1815r2">P1815R2</a>.
It potentially impacts on code written against C++98 and later standards.
</p>

<p>
This feature was deprecated only at the final meeting of the C++20 development
cycle, and at the time this paper is written, there is no experience with how
much code has been impacted by this deprecation.  As such, it is too early to
make any recommendation for a change with respect to this feature.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="review">
<b>EWGI Review:</b>
To be determined...
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.8">Implicit declaration of copy functions [depr.impldec]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++11
</blockquote>

<blockquote class="note">
<b>Warning since:</b>
Clang 10, gcc 9
</blockquote>

<blockquote class="note">
<b>No warnings:</b>
MSVC
</blockquote>

<blockquote class="note">
<b>Not tested:</b>
EDG
</blockquote>


<blockquote class="note">
<b>Relevant issues:</b>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#2132">Core #2132</a>
</blockquote>

<blockquote class="note">
Core issue #2132 was discussed on the EWG telecon of 2020/04/29.  The consensus
on the call was that this is a contentious issue that should be handled by a
paper in its own right.
</blockquote>

<p>
This feature was deprecated towards the end of the C++11 development cycle
by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3203">N3203</a>
and was heavily relied on prior to that.  That said, the deprecated features
are implicitly deleted if any move operations are declared, and users have
become familiar with this idiom over the last decade, and may now find the
older deprecated behavior jarring.
</p>
<p>
When we reviewed this facility for C++20, there was something of an impasse.
There was concern that removing this feature <i>ever</i> would break too much
code to ever consider it.  Conversely, there was no way to achieve a consensus
to undeprecate these features.  Finally, it was noted that no compiler had
ever issued a deprecation warning for these constructs, and all compiler
implementers present opined that they would never implement such a warning,
as it would flag far too much code to be a usable warning.
</p>
<p>
Since then, gcc has indeed implemented the warning, and incorporated into
its <code>-Wall</code> setting, the flag to turn on all the warnings that have
a vanishingly small false-positive rate.  Similarly, Clang 10 has released with
the same warning enabled since R0 of this document was published.  The feedback
from that exercise was that coupling the destructor into the rule to delete
copy operations was indeed far too noisy, and unlikely to be realizable in
production code.  Legitimate use case to implement a destructor unrelated to
copy operation occur too frequently in practice, such as a simple act of
logging or asserting invariants at the end of an object's lifetime.  However,
the coupling of the two copy operations produced a much lower (and tractable)
number of warnings, and found real bugs along with a number of false positives.
</p>
<p>
The workaround for the issue in the vast majority of cases is to simply declare
the other copy member in the class definition as <code>= default</code> so the
fix is (mostly) simple, easily hinted, and modern tools can even offer to apply
the fix for you as part of the warning.  There may be a concern that the fix
relies on a C++11 feature, and so requires more work for code maintaining C++03
compatibility.  This is true, but for C++03 there is no functional difference
between generating the default and writing it by hand.  For C++11 the potential
difference is that a user-provided copy operation is no longer trivial, but the
distinction of decomposing PODs into trivial operations and standard layout
types matters only for C++11 onwards, as user-providing either operation causes
the type to not be a POD in C++03.
</p>

<p>
One unusual case for consideration is an idiom for defining iterator types
where the <code>const_iterator</code> can be implicitly constructed from the
plain <code>iterator</code>.  One way to achieve this is for the two iterators
to be instantiations of the same class template, but with a <code>const</code>
qualified type argument for the <code>const_iterator</code>, and use a
metafunction to produce an alias for the <code>const_iterator</code> in both
cases.  An implicit constructor declared with this aliased name will be a copy
constructor for the plain <code>iterator</code>, or an additional overloaded
constructor for the <code>const_iterator</code>.  However, we cannot declare
both constructors, as in the case of the plain <code>iterator</code> that would
be a duplicate declaration, so for the case of <code>const_iterator</code> we
<i>must</i> rely on the implicit copy constructor declaration.  As the declared
constructor is not the copy constructor for all instantiations, it cannot be
defaulted.  In a common implementation of this idiom we similarly rely on the
implicitly declared copy-assignment operator, which would now have to be
user-declared.  However, due to the declaration matching the signature of the
copy assignment operator for only the <code>iterator</code> instantiations, we
cannot simply default this new declaration, and must explicitly provide a
definition too.
</p>
<blockquote class="note">
<pre>
template&lt;class T&gt;
class MyIterator {
   T * d_ptr = nullptr;

 public:
   using base_iterator = MyIterator&lt;std::remove_const_t&lt;T&gt;&gt;;

   MyIterator() = default;
   explicit MyIterator(T * ptr) : d_ptr{ptr} {}

   MyIterator(base_iterator const &amp; it) : d_ptr{it.operator-&gt;()} {}
     <i>// This is the copy constructor if 'T' is not 'const'-qualified,</i>
     <i>// otherwise the copy constructor is implicitly declared.</i>

   <ins>MyIterator&amp; operator=(base_iterator const &amp; it) {</ins>
     <ins><i>// This is the copy-assignment operator if 'T' is not 'const'-qualified,</i></ins>
     <ins><i>// otherwise the copy-assignment operator is implicitly declared.</i></ins>
     <ins>d_ptr = it.operator-&gt;();</ins>
     <ins>return *this;</ins>
   <ins>}</ins>

   T * operator-&gt;() const noexcept { return d_ptr; }

   <i>// ...</i>
};
</pre>
</blockquote>

<p>
</p>

<p>
The strong recommendation of this paper is mixed: it is time to enforce the
rule coupling the copy operations in the same manner as the move operations are
coupled, and remove the legacy auto-generation if just one is user-defined.
However, at the same time, we should uncouple the destructor from this rule,
undeprecating its impact on copy operations.  We might consider uncoupling the
destructor from move operations for consistency, but that would be a separate
paper.
</p>
<p>
The weak recommendation is to continue another standard cycle with this feature
deprecated as-is, but consider what actions and research might demonstrate we
are ready to remove this coupling for C++26.
</p>

<blockquote class="recommend">
<b>Strong recommendation:</b>
take decisive action early in the C++23 development cycle, so early adopters
can shake out the remaining cost of updating old code.  Note that this would be
both an API and ABI breaking change, and it would be good to set that precedent
early if we wish to allow such breakage in C++23.
</blockquote>

<blockquote class="draft_wording">
<h4>11.4.4.2 Copy/move constructors [class.copy.ctor]</h4>
<ol start="6">
<li>
<p><del>
If the class definition does not explicitly declare a copy constructor, a
non-explicit one is declared <i>implicitly</i>. If the class definition
declares a move constructor or move assignment operator, the implicitly
declared copy constructor is defined as deleted; otherwise, it is defined as
defaulted (9.5). The latter case is deprecated if the class has a user-declared
copy assignment operator or a user-declared destructor.
</del></p>
<p><ins>
If the definition of a class <code>X</code> does not explicitly declare a copy
constructor, a non-explicit one will be implicitly declared as defaulted if and
only if
</ins></p>
  <ol>
  <li><ins>&mdash; <code>X</code> does not have a user-declared copy assignment operator,</ins></li>
  <li><ins>&mdash; <code>X</code> does not have a user-declared move constructor, and</ins></li>
  <li><ins>&mdash; <code>X</code> does not have a user-declared move assignment operator.</ins></li>
  </ol>
  <blockquote class="note">
  User declared destructors are deliberately omitted from this list.  This
  wording undeprecates that concern - we could insert additional wording to
  retain the deprecated status when the class has a user-declared destructor.
  Note that we probably want the term "user-provided" as a user-declared
  <code>= default</code> destructor should not be a concern.
  </blockquote>
</li>
</ol>

<h4>11.4.5 Copy/move assignment operator [class.copy.assign]</h4>
<ol start="2">
<li>
<p><del>
If the class definition does not explicitly declare a copy assignment operator,
one is declared <i>implicitly</i>. If the class definition declares a move
constructor or move assignment operator, the implicitly declared copy
assignment operator is defined as deleted; otherwise, it is defined as
defaulted (9.5).  The latter case is deprecated if the class has a
user-declared copy constructor or a user-declared destructor.
</del></p>
<p><ins>
If the definition of a class <code>X</code> does not explicitly declare a copy
assignment operator, one will be implicitly declared as defaulted if and only if
</ins></p>
  <ol>
  <li><ins>&mdash; <code>X</code> does not have a user-declared copy constructor,</ins></li>
  <li><ins>&mdash; <code>X</code> does not have a user-declared move constructor, and</ins></li>
  <li><ins>&mdash; <code>X</code> does not have a user-declared move assignment operator.</ins></li>
  </ol>
  <blockquote class="note">
  User declared destructors are deliberately omitted from this list.  This
  wording undeprecates that concern - we could insert additional wording to
  retain the deprecated status when the class has a user-declared destructor.
  Note that we probably want the term "user-provided" as a user-declared
  <code>= default</code> destructor should not be a concern.
  </blockquote>
</li>
<li>
The implicitly-declared copy assignment operator for a class <code>X</code> will
have the form...
</li>
</ol>


<h4><del>D.8 Implicit declaration of copy functions [depr.impldec]</del></h4>
<ol>
<li><del>
The implicit definition of a copy constructor as defaulted is deprecated if the
class has a user-declared copy assignment operator or a user-declared
destructor. The implicit definition of a copy assignment operator as defaulted
is deprecated if the class has a user-declared copy constructor or a
user-declared destructor (15.4, 15.8). In a future revision of this
International Standard, these implicit definitions could become deleted (11.4).
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action now, and plan to remove this feature in the next revision of the
standard that will permit both ABI and API breakage.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="review">
<b>EWGI Review:</b>
To be determined...
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.9">C headers [depr.c.headers]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++98
</blockquote>

<p>
The basic C library headers are an essential compatibility feature, and not
going anywhere anytime soon.  However, there are certain C++ specific
counterparts that do not bring value, particularly where the corresponding C
header's job is to supply macros that masquerade as keywords already present in
the C++ language.
</p>

<p>
One possibility to be more aggressive here, following the decision to not adopt
<i>all</i> C11 headers as part of the C++ mapping to C, would be to remove
those same C headers from the subset that must be shipped with a C++ compiler.
The corresponding change for the C++ <code>&lt;cstd*&gt;</code> was accepted for
C++20.  This would not prevent those headers being supplied, as part of a full
C implementation, but would indicate that they have no value to a C++ system.
</p>

<p>
Finally, it seems clear that the C headers will be retained essentially
forever, as a vital compatibility layer with C and POSIX.  After two decades of
deprecation, not a single compiler provides a deprecation warning on including
these headers, and it is difficult to imagine circumstances where they would,
as any use of a third party C library by a C++ project is almost guaranteed to
include one of these headers, at least indirectly.  Therefore, it seems
appropriate to undeprecate the headers, and find a home for them as a
compatibility layer in the main standard.  It is also possible that we will
want to explore a different approach in the future once modules are part of
C++, and the library is updated to properly take advantage of the new language
feature.
</p>

<p>
The strong recommendation of this paper is to undeprecate the C library as an
essential compatibility layer with the rest of the world, optionally removing
the vacuous headers.  A note in favor of removing the vacuous headers is that
the C standard itself is moving in the direction of adopting the
&quot;regular&quot; keywords, and hollowing out and deprecating the headers
<code>&lt;stdalign.h&gt;</code> and <code>&lt;stdbool.h&gt;</code> for C2X. See
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2458.pdf">WG14:N2457</a>
and
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2458.pdf">WG14:N2458</a>
for more details.
</p>
<p>
The weak recommendation is to remove these entirely from C++23: these headers
are already owned and specified by at least two other ISO committees, and while
C compatibility is an essential feature for any C++ tool chain sitting on POSIX,
it may be over-specification demanding what should be platform implementation
details for other environments - as noted when C++17 chose to not require the
C <code>&lt;atomic.h&gt;</code>.
</p>


<blockquote class="recommend">
<b>Strong recommendation(A):</b>
Remove the vacuous headers, then undeprecate the remaining
<b>[depr.c.headers]</b> and move directly into 16.5.5.2
<b>[res.on.headers]</b>.
</blockquote>

<blockquote class="draft_wording">
<h4><ins>16.5.5.2.1 C standard library headers [c.headers]</ins></h4>
<ol>
<li><ins>
For compatibility with the C standard library, the C++ standard library
provides the C headers shown in Table 147.
</ins>
<table>
  <caption><ins>Table 147 &mdash; C headers [tab:depr.c.headers]</ins></caption>
  <tr>
    <td><code><ins>&lt;assert.h&gt;</ins></code></td>
    <td><code><ins>&lt;inttypes.h&gt;</ins></code></td>
    <td><code><ins>&lt;signal.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdio.h&gt;</ins></code></td>
    <td><code><ins>&lt;wchar.h&gt;</ins></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;complex.h&gt;</del></code></td>
    <td><code><del>&lt;iso646.h&gt;</del></code></td>
    <td><code><del>&lt;stdalign.h&gt;</del></code></td>
    <td><code><ins>&lt;stdlib.h&gt;</ins></code></td>
    <td><code><ins>&lt;wctype.h&gt;</ins></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;ctype.h&gt;</ins></code></td>
    <td><code><ins>&lt;limits.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdarg.h&gt;</ins></code></td>
    <td><code><ins>&lt;string.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;errno.h&gt;</ins></code></td>
    <td><code><ins>&lt;locale.h&gt;</ins></code></td>
    <td><code><del>&lt;stdbool.h&gt;</del></code></td>
    <td><code><del>&lt;tgmath.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;fenv.h&gt;</ins></code></td>
    <td><code><ins>&lt;math.h&gt;</ins></code></td>
    <td><code><ins>&lt;stddef.h&gt;</ins></code></td>
    <td><code><ins>&lt;time.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;float.h&gt;</ins></code></td>
    <td><code><ins>&lt;setjmp.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdint.h&gt;</ins></code></td>
    <td><code><ins>&lt;uchar.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
</table>
</li>
<li><ins>
Every C header, each of which has a name of the form <code>&lt;name.h&gt;</code>,
behaves as if each name placed in the standard library namespace by the
corresponding <code>&lt;cname&gt;</code> header is placed within the global
namespace scope, except for the functions described in 26.8.6, the declarations
of <code>std::nullptr_t</code> (17.2.3) and <code>std::byte</code> (17.2.5),
and the functions and function templates described in 17.2.5. It is unspecified
whether these names are first declared or defined within namespace scope
(6.4.6) of the namespace <code>std</code> and are then injected into the global
namespace scope by explicit using-declarations (9.9).
</ins></li>
<li><ins>
[<i>Example:</i> The header <code>&lt;cstdlib&gt;</code> assuredly provides its
declarations and definitions within the namespace <code>std</code>. It may also
provide these names within the global namespace. The header
<code>&lt;stdlib.h&gt;</code> assuredly provides the same declarations and
definitions within the global namespace, much as in the C Standard. It may also
provide these names within the namespace <code>std</code>. <i>&mdash;end
example</i>]
</ins></li>
</ol>


<h4>C.6.1 Modifications to headers [diff.mods.to.headers]</h4>
<ol>
<li>
For compatibility with the C standard library, the C++ standard library
provides the C headers enumerated in <del>D.9, but their use is deprecated in
C++</del>
<ins><b>[c.headers]</b></ins>.
</li>
<li>
There are no C++ headers for the C headers
<ins><code>&lt;complex.h&gt;</code>, <code>&lt;iso646.h&gt;</code>,
<code>&lt;stdalign.h&gt;</code>,</ins> <code>&lt;stdatomic.h&gt;</code>,
<ins><code>&lt;stdbool.h&gt;</code>,</ins> <code>&lt;stdnoreturn.h&gt;</code>,
<ins><code>&lt;tgmath.h&gt;</code>,</ins> and <code>&lt;threads.h&gt;</code>,
nor are these headers from the C standard library headers themselves part of
C++.
</li>
<li><del>
The C headers <code>&lt;complex.h&gt;</code> and <code>&lt;tgmath.h&gt;</code>
do not contain any of the content from the C standard library and instead
merely include other headers from the C++ standard library.
</del></li>
</ol>


<h4><del>D.9 C headers [depr.c.headers]</del></h4>
<ol>
<li><del>
For compatibility with the C standard library, the C++ standard library
provides the <i>C headers</i> shown in Table 147.
</del>
<table>
  <caption><del>Table 147 &mdash; C headers [tab:depr.c.headers]</del></caption>
  <tr>
    <td><code><del>&lt;assert.h&gt;</del></code></td>
    <td><code><del>&lt;inttypes.h&gt;</del></code></td>
    <td><code><del>&lt;signal.h&gt;</del></code></td>
    <td><code><del>&lt;stdio.h&gt;</del></code></td>
    <td><code><del>&lt;wchar.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;complex.h&gt;</del></code></td>
    <td><code><del>&lt;iso646.h&gt;</del></code></td>
    <td><code><del>&lt;stdalign.h&gt;</del></code></td>
    <td><code><del>&lt;stdlib.h&gt;</del></code></td>
    <td><code><del>&lt;wctype.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;ctype.h&gt;</del></code></td>
    <td><code><del>&lt;limits.h&gt;</del></code></td>
    <td><code><del>&lt;stdarg.h&gt;</del></code></td>
    <td><code><del>&lt;string.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;errno.h&gt;</del></code></td>
    <td><code><del>&lt;locale.h&gt;</del></code></td>
    <td><code><del>&lt;stdbool.h&gt;</del></code></td>
    <td><code><del>&lt;tgmath.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;fenv.h&gt;</del></code></td>
    <td><code><del>&lt;math.h&gt;</del></code></td>
    <td><code><del>&lt;stddef.h&gt;</del></code></td>
    <td><code><del>&lt;time.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;float.h&gt;</del></code></td>
    <td><code><del>&lt;setjmp.h&gt;</del></code></td>
    <td><code><del>&lt;stdint.h&gt;</del></code></td>
    <td><code><del>&lt;uchar.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
</table>
</li>
</ol>

<h4><del>D.9.1 Header <code>&lt;complex.h&gt;</code> synopsis [depr.complex.h.syn]</del></h4>
<pre><del>#include <code>&lt;complex&gt;</code></del></pre>
<ol>
<li><del>
The header <code>&lt;complex.h&gt;</code> behaves as if it simply includes the
header <code>&lt;complex&gt;</code> (26.4.1).
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;complex&gt;</code> in namespace
<code>std</code> are not placed into the global namespace scope by
<code>&lt;complex.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.2 Header <code>&lt;iso646.h&gt;</code> synopsis [depr.iso646.h.syn]</del></h4>
<ol>
<li><del>
The C++ header <code>&lt;iso646.h&gt;</code> is empty. [<i>Note:</i>
<code>and</code>, <code>and_eq</code>, <code>bitand</code>, <code>bitor</code>,
<code>compl</code>, <code>not_eq</code>, <code>not</code>, <code>or</code>,
<code>or_eq</code>, <code>xor</code>, and <code>xor_eq</code> are keywords in
this International Standard (5.11). <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.3 Header <code>&lt;stdalign.h&gt;</code> synopsis [depr.stdalign.h.syn]</del></h4>
<pre><del>#define __alignas_is_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdalign.h&gt;</code> are the same as
the C standard library header <code>&lt;stdalign.h&gt;</code>, with the
following changes: The header <code>&lt;stdalign.h&gt;</code> does not define a
macro named alignas.</del>
<p><del>See also: ISO C 7.15</del></p>
</li>
</ol>


<h4><del>D.9.4 Header <code>&lt;stdbool.h&gt;</code> synopsis [depr.stdbool.h.syn]</del></h4>
<pre><del>#define __bool_true_false_are_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdbool.h&gt;</code> are the same as
the C standard library header <code>&lt;stdbool.h&gt;</code>, with the
following changes: The header <code>&lt;stdbool.h&gt;</code> does not define
macros named <code>bool</code>, <code>true</code>, or <code>false</code>.</del>
<p><del>See also: ISO C 7.18</del></p>
</li>
</ol>


<h4><del>D.9.5 Header <code>&lt;tgmath.h&gt;</code> synopsis [depr.tgmath.h.syn]</del></h4>
<pre>
<del>#include <code>&lt;cmath&gt;</code></del>
<del>#include <code>&lt;complex&gt;</code></del>
</pre>
<ol>
<li><del>
The header <code>&lt;tgmath.h&gt;</code> behaves as if it simply includes the
headers <code>&lt;cmath&gt;</code> (26.8.1) and <code>&lt;complex&gt;</code>
(26.4.1).
</del></li>
<li><del>
[<i>Note:</i> The overloads provided in C by type-generic macros are already
provided in <code>&lt;complex&gt;</code> and <code>&lt;cmath&gt;</code> by
“sufficient” additional overloads. <i>&mdash;end note</i>]
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;cmath&gt;</code> or
<code>&lt;complex&gt;</code> in namespace std are not placed into the global
namespace scope by <code>&lt;tgmath.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.6 Other C headers [depr.c.headers.other]</del></h4>
<ol>
<li><del>
Every C header other than <code>&lt;complex.h&gt;</code> (D.9.1),
<code>&lt;iso646.h&gt;</code> (D.9.2), <code>&lt;stdalign.h&gt;</code> (D.9.3),
<code>&lt;stdbool.h&gt;</code> (D.9.4), and <code>&lt;tgmath.h&gt;</code>
(D.9.5), each of which has a name of the form
<code>&lt;<i>name</i>.h&gt;</code>, behaves as if each name placed in the
standard library namespace by the corresponding
<code>&lt;<i>cname</i>&gt;</code> header is placed within the global namespace
scope, except for the functions described in 26.8.6, the declaration of
<code>std::byte</code> (17.2.1), and the functions and function templates
described in 17.2.5. It is unspecified whether these names are first declared
or defined within namespace scope (6.4.6) of the namespace <code>std</code> and
are then injected into the global namespace scope by explicit
<i>using-declarations</i> (9.9).
</del></li>
<li><del>
[<i>Example:</i> The header <code>&lt;cstdlib&gt;</code> assuredly provides its
declarations and definitions within the namespace <code>std</code>. It may also
provide these names within the global namespace. The header
<code>&lt;stdlib.h&gt;</code> assuredly provides the same declarations and
definitions within the global namespace, much as in the C Standard. It may also
provide these names within the namespace <code>std</code>. <i>&mdash;end
example</i>]
</del></li>
</ol>
</blockquote>


<blockquote class="recommend">
<b>strong recommendation (B):</b>
Undeprecate the remaining <b>[depr.c.headers]</b> and move directly into
16.5.5.2 <b>[res.on.headers]</b>.
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.5.2 Headers [res.on.headers]</h4>
<ol>
<li>
A C++ header may include other C++ headers. A C++ header shall provide the
declarations and definitions that appear in its synopsis. A C++ header shown in
its synopsis as including other C++ headers shall provide the declarations and
definitions that appear in the synopses of those other headers.
</li>
<li>
Certain types and macros are defined in more than one header. Every such entity
shall be defined such that any header that defines it may be included after any
other header that also defines it (6.3).
</li>
<li><del>
The C standard library headers (D.9) shall include only their corresponding C++
standard library header, as described in 16.5.1.2.
</del></li>
</ol>

<blockquote class="note">
Actually, probably want to merge this into <b>16.5.1.2 Headers [headers]</b>.
Also, fix up cross-references to list stable labels.
</blockquote>
<h4><ins>16.5.5.2.1 C headers [c.headers]</ins></h4>
<ol>
<li><ins>
For compatibility with the C standard library, the C++ standard library
provides the <i>C headers</i> shown in Table 147.
</ins>
<table>
  <caption><ins>Table 147 &mdash; C headers [tab:depr.c.headers]</ins></caption>
  <tr>
    <td><code><ins>&lt;assert.h&gt;</ins></code></td>
    <td><code><ins>&lt;inttypes.h&gt;</ins></code></td>
    <td><code><ins>&lt;signal.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdio.h&gt;</ins></code></td>
    <td><code><ins>&lt;wchar.h&gt;</ins></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;complex.h&gt;</ins></code></td>
    <td><code><ins>&lt;iso646.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdalign.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdlib.h&gt;</ins></code></td>
    <td><code><ins>&lt;wctype.h&gt;</ins></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;ctype.h&gt;</ins></code></td>
    <td><code><ins>&lt;limits.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdarg.h&gt;</ins></code></td>
    <td><code><ins>&lt;string.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;errno.h&gt;</ins></code></td>
    <td><code><ins>&lt;locale.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdbool.h&gt;</ins></code></td>
    <td><code><ins>&lt;tgmath.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;fenv.h&gt;</ins></code></td>
    <td><code><ins>&lt;math.h&gt;</ins></code></td>
    <td><code><ins>&lt;stddef.h&gt;</ins></code></td>
    <td><code><ins>&lt;time.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><ins>&lt;float.h&gt;</ins></code></td>
    <td><code><ins>&lt;setjmp.h&gt;</ins></code></td>
    <td><code><ins>&lt;stdint.h&gt;</ins></code></td>
    <td><code><ins>&lt;uchar.h&gt;</ins></code></td>
    <td><code></code></td>
  </tr>
</table>
</li>
</ol>

<h4><ins>16.5.5.2.1.1 Header <code>&lt;complex.h&gt;</code> synopsis [complex.h.syn]</ins></h4>
<pre><ins>#include <code>&lt;complex&gt;</code></ins></pre>
<ol>
<li><ins>
The header <code>&lt;complex.h&gt;</code> behaves as if it simply includes the
header <code>&lt;complex&gt;</code> (26.4.1).
</ins></li>
<li><ins>
[<i>Note:</i> Names introduced by <code>&lt;complex&gt;</code> in namespace
<code>std</code> are not placed into the global namespace scope by
<code>&lt;complex.h&gt;</code>. <i>&mdash;end note</i>]
</ins></li>
</ol>

<h4><ins>16.5.5.2.1.2 Header <code>&lt;iso646.h&gt;</code> synopsis [iso646.h.syn]</ins></h4>
<ol>
<li><ins>
The C++ header <code>&lt;iso646.h&gt;</code> is empty. [<i>Note:</i>
<code>and</code>, <code>and_eq</code>, <code>bitand</code>, <code>bitor</code>,
<code>compl</code>, <code>not_eq</code>, <code>not</code>, <code>or</code>,
<code>or_eq</code>, <code>xor</code>, and <code>xor_eq</code> are keywords in
this International Standard (5.11). <i>&mdash;end note</i>]
</ins></li>
</ol>

<h4><ins>16.5.5.2.1.3 Header <code>&lt;stdalign.h&gt;</code> synopsis [stdalign.h.syn]</ins></h4>
<pre><ins>#define __alignas_is_defined 1</ins></pre>
<ol>
<li><ins>
The contents of the C++ header <code>&lt;stdalign.h&gt;</code> are the same as
the C standard library header <code>&lt;stdalign.h&gt;</code>, with the
following changes: The header <code>&lt;stdalign.h&gt;</code> does not define a
macro named alignas.</ins>
<p><ins>See also: ISO C 7.15</ins></p>
</li>
</ol>

<h4><ins>16.5.5.2.1.4 Header <code>&lt;stdbool.h&gt;</code> synopsis [stdbool.h.syn]</ins></h4>
<pre><ins>#define __bool_true_false_are_defined 1</ins></pre>
<ol>
<li><ins>
The contents of the C++ header <code>&lt;stdbool.h&gt;</code> are the same as
the C standard library header <code>&lt;stdbool.h&gt;</code>, with the
following changes: The header <code>&lt;stdbool.h&gt;</code> does not define
macros named <code>bool</code>, <code>true</code>, or <code>false</code>.</ins>
<p><ins>See also: ISO C 7.18</ins></p>
</li>
</ol>

<h4><ins>16.5.5.2.1.5 Header <code>&lt;tgmath.h&gt;</code> synopsis [tgmath.h.syn]</ins></h4>
<pre>
<ins>#include <code>&lt;cmath&gt;</code></ins>
<ins>#include <code>&lt;complex&gt;</code></ins>
</pre>
<ol>
<li><ins>
The header <code>&lt;tgmath.h&gt;</code> behaves as if it simply includes the
headers <code>&lt;cmath&gt;</code> (26.8.1) and <code>&lt;complex&gt;</code>
(26.4.1).
</ins></li>
<li><ins>
[<i>Note:</i> The overloads provided in C by type-generic macros are already
provided in <code>&lt;complex&gt;</code> and <code>&lt;cmath&gt;</code> by
"sufficient" additional overloads. <i>&mdash;end note</i>]
</ins></li>
<li><ins>
[<i>Note:</i> Names introduced by <code>&lt;cmath&gt;</code> or
<code>&lt;complex&gt;</code> in namespace std are not placed into the global
namespace scope by <code>&lt;tgmath.h&gt;</code>. <i>&mdash;end note</i>]
</ins></li>
</ol>

<h4><ins>16.5.5.2.1.6 Other C headers [c.headers.other]</ins></h4>
<ol>
<li><ins>
Every C header other than <code>&lt;complex.h&gt;</code> (D.9.1),
<code>&lt;iso646.h&gt;</code> (D.9.2), <code>&lt;stdalign.h&gt;</code> (D.9.3),
<code>&lt;stdbool.h&gt;</code> (D.9.4), and <code>&lt;tgmath.h&gt;</code>
(D.9.5), each of which has a name of the form
<code>&lt;<i>name</i>.h&gt;</code>, behaves as if each name placed in the
standard library namespace by the corresponding
<code>&lt;<i>cname</i>&gt;</code> header is placed within the global namespace
scope, except for the functions described in 26.8.6, the declaration of
<code>std::byte</code> (17.2.1), and the functions and function templates
described in 17.2.5. It is unspecified whether these names are first declared
or defined within namespace scope (6.4.6) of the namespace <code>std</code> and
are then injected into the global namespace scope by explicit
<i>using-declarations</i> (9.9).
</ins></li>
<li><ins>
[<i>Example:</i> The header <code>&lt;cstdlib&gt;</code> assuredly provides its
declarations and definitions within the namespace <code>std</code>. It may also
provide these names within the global namespace. The header
<code>&lt;stdlib.h&gt;</code> assuredly provides the same declarations and
definitions within the global namespace, much as in the C Standard. It may also
provide these names within the namespace <code>std</code>. <i>&mdash;end
example</i>]
</ins></li>
</ol>


<h4><del>D.9 C headers [depr.c.headers]</del></h4>
<ol>
<li><del>
For compatibility with the C standard library, the C++ standard library
provides the <i>C headers</i> shown in Table 147.
</del>
<table>
  <caption><del>Table 147 &mdash; C headers [tab:depr.c.headers]</del></caption>
  <tr>
    <td><code><del>&lt;assert.h&gt;</del></code></td>
    <td><code><del>&lt;inttypes.h&gt;</del></code></td>
    <td><code><del>&lt;signal.h&gt;</del></code></td>
    <td><code><del>&lt;stdio.h&gt;</del></code></td>
    <td><code><del>&lt;wchar.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;complex.h&gt;</del></code></td>
    <td><code><del>&lt;iso646.h&gt;</del></code></td>
    <td><code><del>&lt;stdalign.h&gt;</del></code></td>
    <td><code><del>&lt;stdlib.h&gt;</del></code></td>
    <td><code><del>&lt;wctype.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;ctype.h&gt;</del></code></td>
    <td><code><del>&lt;limits.h&gt;</del></code></td>
    <td><code><del>&lt;stdarg.h&gt;</del></code></td>
    <td><code><del>&lt;string.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;errno.h&gt;</del></code></td>
    <td><code><del>&lt;locale.h&gt;</del></code></td>
    <td><code><del>&lt;stdbool.h&gt;</del></code></td>
    <td><code><del>&lt;tgmath.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;fenv.h&gt;</del></code></td>
    <td><code><del>&lt;math.h&gt;</del></code></td>
    <td><code><del>&lt;stddef.h&gt;</del></code></td>
    <td><code><del>&lt;time.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;float.h&gt;</del></code></td>
    <td><code><del>&lt;setjmp.h&gt;</del></code></td>
    <td><code><del>&lt;stdint.h&gt;</del></code></td>
    <td><code><del>&lt;uchar.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
</table>
</li>
</ol>

<h4><del>D.9.1 Header <code>&lt;complex.h&gt;</code> synopsis [depr.complex.h.syn]</del></h4>
<pre><del>#include <code>&lt;complex&gt;</code></del></pre>
<ol>
<li><del>
The header <code>&lt;complex.h&gt;</code> behaves as if it simply includes the
header <code>&lt;complex&gt;</code> (26.4.1).
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;complex&gt;</code> in namespace
<code>std</code> are not placed into the global namespace scope by
<code>&lt;complex.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.2 Header <code>&lt;iso646.h&gt;</code> synopsis [depr.iso646.h.syn]</del></h4>
<ol>
<li><del>
The C++ header <code>&lt;iso646.h&gt;</code> is empty. [<i>Note:</i>
<code>and</code>, <code>and_eq</code>, <code>bitand</code>, <code>bitor</code>,
<code>compl</code>, <code>not_eq</code>, <code>not</code>, <code>or</code>,
<code>or_eq</code>, <code>xor</code>, and <code>xor_eq</code> are keywords in
this International Standard (5.11). <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.3 Header <code>&lt;stdalign.h&gt;</code> synopsis [depr.stdalign.h.syn]</del></h4>
<pre><del>#define __alignas_is_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdalign.h&gt;</code> are the same as
the C standard library header <code>&lt;stdalign.h&gt;</code>, with the
following changes: The header <code>&lt;stdalign.h&gt;</code> does not define a
macro named alignas.</del>
<p><del>See also: ISO C 7.15</del></p>
</li>
</ol>


<h4><del>D.9.4 Header <code>&lt;stdbool.h&gt;</code> synopsis [depr.stdbool.h.syn]</del></h4>
<pre><del>#define __bool_true_false_are_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdbool.h&gt;</code> are the same as
the C standard library header <code>&lt;stdbool.h&gt;</code>, with the
following changes: The header <code>&lt;stdbool.h&gt;</code> does not define
macros named <code>bool</code>, <code>true</code>, or <code>false</code>.</del>
<p><del>See also: ISO C 7.18</del></p>
</li>
</ol>


<h4><del>D.9.5 Header <code>&lt;tgmath.h&gt;</code> synopsis [depr.tgmath.h.syn]</del></h4>
<pre>
<del>#include <code>&lt;cmath&gt;</code></del>
<del>#include <code>&lt;complex&gt;</code></del>
</pre>
<ol>
<li><del>
The header <code>&lt;tgmath.h&gt;</code> behaves as if it simply includes the
headers <code>&lt;cmath&gt;</code> (26.8.1) and <code>&lt;complex&gt;</code>
(26.4.1).
</del></li>
<li><del>
[<i>Note:</i> The overloads provided in C by type-generic macros are already
provided in <code>&lt;complex&gt;</code> and <code>&lt;cmath&gt;</code> by
"sufficient" additional overloads. <i>&mdash;end note</i>]
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;cmath&gt;</code> or
<code>&lt;complex&gt;</code> in namespace std are not placed into the global
namespace scope by <code>&lt;tgmath.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.6 Other C headers [depr.c.headers.other]</del></h4>
<ol>
<li><del>
Every C header other than <code>&lt;complex.h&gt;</code> (D.9.1),
<code>&lt;iso646.h&gt;</code> (D.9.2), <code>&lt;stdalign.h&gt;</code> (D.9.3),
<code>&lt;stdbool.h&gt;</code> (D.9.4), and <code>&lt;tgmath.h&gt;</code>
(D.9.5), each of which has a name of the form <code>&lt;name.h&gt;</code>,
behaves as if each name placed in the standard library namespace by the
corresponding <code>&lt;cname&gt;</code> header is placed within the global
namespace scope, except for the functions described in 26.8.6, the declaration
of <code>std::byte</code> (17.2.1), and the functions and function templates
described in 17.2.5. It is unspecified whether these names are first declared
or defined within namespace scope (6.4.6) of the namespace <code>std</code> and
are then injected into the global namespace scope by explicit
using-declarations (9.9).
</del></li>
<li><del>
[<i>Example:</i> The header <code>&lt;cstdlib&gt;</code> assuredly provides its
declarations and definitions within the namespace <code>std</code>. It may also
provide these names within the global namespace. The header
<code>&lt;stdlib.h&gt;</code> assuredly provides the same declarations and
definitions within the global namespace, much as in the C Standard. It may also
provide these names within the namespace <code>std</code>. <i>&mdash;end
example</i>]
</del></li>
</ol>
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove entirely from C++23.
</blockquote>

<blockquote class="draft_wording">
<h4>C.6.1 Modifications to headers [diff.mods.to.headers]</h4>
<ol>
<li>
For compatibility with the C standard library, the C++ standard library
provides the C headers enumerated in <del>D.9, but their use is deprecated in
C++</del><ins><b>[c.headers]</b></ins>.
</li>
<li><del>
There are no C++ headers for the C headers <code>&lt;stdatomic.h&gt;</code>,
<code>&lt;stdnoreturn.h&gt;</code>, and <code>&lt;threads.h&gt;</code>, nor are
the C headers themselves part of C++.
</del></li>
<li><del>
The C headers <code>&lt;complex.h&gt;</code> and <code>&lt;tgmath.h&gt;</code>
do not contain any of the content from the C standard library and instead
merely include other headers from the C++ standard library.
</del></li>
</ol>

<blockquote class="note">
Revise compatibility note for Annex C.  This wording needs a little more
thought.
</blockquote>


<h4><del>D.9 C headers [depr.c.headers]</del></h4>
<ol>
<li><del>
For compatibility with the C standard library, the C++ standard library
provides the <i>C headers</i> shown in Table 147.
</del>
<table>
  <caption><del>Table 147 &mdash; C headers [tab:depr.c.headers]</del></caption>
  <tr>
    <td><code><del>&lt;assert.h&gt;</del></code></td>
    <td><code><del>&lt;inttypes.h&gt;</del></code></td>
    <td><code><del>&lt;signal.h&gt;</del></code></td>
    <td><code><del>&lt;stdio.h&gt;</del></code></td>
    <td><code><del>&lt;wchar.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;complex.h&gt;</del></code></td>
    <td><code><del>&lt;iso646.h&gt;</del></code></td>
    <td><code><del>&lt;stdalign.h&gt;</del></code></td>
    <td><code><del>&lt;stdlib.h&gt;</del></code></td>
    <td><code><del>&lt;wctype.h&gt;</del></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;ctype.h&gt;</del></code></td>
    <td><code><del>&lt;limits.h&gt;</del></code></td>
    <td><code><del>&lt;stdarg.h&gt;</del></code></td>
    <td><code><del>&lt;string.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;errno.h&gt;</del></code></td>
    <td><code><del>&lt;locale.h&gt;</del></code></td>
    <td><code><del>&lt;stdbool.h&gt;</del></code></td>
    <td><code><del>&lt;tgmath.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;fenv.h&gt;</del></code></td>
    <td><code><del>&lt;math.h&gt;</del></code></td>
    <td><code><del>&lt;stddef.h&gt;</del></code></td>
    <td><code><del>&lt;time.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
  <tr>
    <td><code><del>&lt;float.h&gt;</del></code></td>
    <td><code><del>&lt;setjmp.h&gt;</del></code></td>
    <td><code><del>&lt;stdint.h&gt;</del></code></td>
    <td><code><del>&lt;uchar.h&gt;</del></code></td>
    <td><code></code></td>
  </tr>
</table>
</li>
</ol>

<h4><del>D.9.1 Header <code>&lt;complex.h&gt;</code> synopsis [depr.complex.h.syn]</del></h4>
<pre><del>#include <code>&lt;complex&gt;</code></del></pre>
<ol>
<li><del>
The header <code>&lt;complex.h&gt;</code> behaves as if it simply includes the
header <code>&lt;complex&gt;</code> (26.4.1).
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;complex&gt;</code> in namespace
<code>std</code> are not placed into the global namespace scope by
<code>&lt;complex.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.2 Header <code>&lt;iso646.h&gt;</code> synopsis [depr.iso646.h.syn]</del></h4>
<ol>
<li><del>
The C++ header <code>&lt;iso646.h&gt;</code> is empty. [<i>Note:</i>
<code>and</code>, <code>and_eq</code>, <code>bitand</code>, <code>bitor</code>,
<code>compl</code>, <code>not_eq</code>, <code>not</code>, <code>or</code>,
<code>or_eq</code>, <code>xor</code>, and <code>xor_eq</code> are keywords in
this International Standard (5.11). <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.3 Header <code>&lt;stdalign.h&gt;</code> synopsis [depr.stdalign.h.syn]</del></h4>
<pre><del>#define __alignas_is_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdalign.h&gt;</code> are the same as
the C standard library header <code>&lt;stdalign.h&gt;</code>, with the
following changes: The header <code>&lt;stdalign.h&gt;</code> does not define a
macro named alignas.</del>
<p><del>See also: ISO C 7.15</del></p>
</li>
</ol>


<h4><del>D.9.4 Header <code>&lt;stdbool.h&gt;</code> synopsis [depr.stdbool.h.syn]</del></h4>
<pre><del>#define __bool_true_false_are_defined 1</del></pre>
<ol>
<li><del>
The contents of the C++ header <code>&lt;stdbool.h&gt;</code> are the same as
the C standard library header <code>&lt;stdbool.h&gt;</code>, with the
following changes: The header <code>&lt;stdbool.h&gt;</code> does not define
macros named <code>bool</code>, <code>true</code>, or <code>false</code>.</del>
<p><del>See also: ISO C 7.18</del></p>
</li>
</ol>


<h4><del>D.9.5 Header <code>&lt;tgmath.h&gt;</code> synopsis [depr.tgmath.h.syn]</del></h4>
<pre>
<del>#include <code>&lt;cmath&gt;</code></del>
<del>#include <code>&lt;complex&gt;</code></del>
</pre>
<ol>
<li><del>
The header <code>&lt;tgmath.h&gt;</code> behaves as if it simply includes the
headers <code>&lt;cmath&gt;</code> (26.8.1) and <code>&lt;complex&gt;</code>
(26.4.1).
</del></li>
<li><del>
[<i>Note:</i> The overloads provided in C by type-generic macros are already
provided in <code>&lt;complex&gt;</code> and <code>&lt;cmath&gt;</code> by
"sufficient" additional overloads. <i>&mdash;end note</i>]
</del></li>
<li><del>
[<i>Note:</i> Names introduced by <code>&lt;cmath&gt;</code> or
<code>&lt;complex&gt;</code> in namespace std are not placed into the global
namespace scope by <code>&lt;tgmath.h&gt;</code>. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.9.6 Other C headers [depr.c.headers.other]</del></h4>
<ol>
<li><del>
Every C header other than <code>&lt;complex.h&gt;</code> (D.9.1),
<code>&lt;iso646.h&gt;</code> (D.9.2), <code>&lt;stdalign.h&gt;</code> (D.9.3),
<code>&lt;stdbool.h&gt;</code> (D.9.4), and <code>&lt;tgmath.h&gt;</code>
(D.9.5), each of which has a name of the form <code>&lt;name.h&gt;</code>,
behaves as if each name placed in the standard library namespace by the
corresponding <code>&lt;cname&gt;</code> header is placed within the global
namespace scope, except for the functions described in 26.8.6, the declaration
of <code>std::byte</code> (17.2.1), and the functions and function templates
described in 17.2.5. It is unspecified whether these names are first declared
or defined within namespace scope (6.4.6) of the namespace <code>std</code> and
are then injected into the global namespace scope by explicit
using-declarations (9.9).
</del></li>
<li><del>
[<i>Example:</i> The header <code>&lt;cstdlib&gt;</code> assuredly provides its
declarations and definitions within the namespace <code>std</code>. It may also
provide these names within the global namespace. The header
<code>&lt;stdlib.h&gt;</code> assuredly provides the same declarations and
definitions within the global namespace, much as in the C Standard. It may also
provide these names within the namespace <code>std</code>. <i>&mdash;end
example</i>]
</del></li>
</ol>
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
There was general agreement that <i>deprecated</i> does not adequately capture
the intent here.  The need for C compatibility means these headers are not
going away, yet some have strong concerns about undeprecating these headers
implying that these are perfectly good for C++ use.  Those concerns are not
reduced by folks like the author believing that is indeed the case.  There was
also the observation that such arguments about best practice are more suited to
education material than the standard proper.  One final observation is that
perhaps these headers could move into Annex C, although that is a non-normative
annex, so the status of such a move might be unclear.
</p>

<p>
Consensus on the call was that this is a big enough topic to merit a new paper
in its own right, and no action should be taken as part of this omnibus
proposal.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Take not action now, and follow up with a specific paper.
</blockquote>

<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.10">Requires paragraph [depr.res.on.required]</h3>
<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This style of documentation was deprecated editorially following the
application of a sequence of papers to update each main library clause,
consistently following the new conventions established by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0788r3">P0788R3</a>
</p>

<p>
Note that no review of this section will be needed if the options to remove all
of D.11, D.13, D.18, D.21, and D.23 are accepted, as there would be nothing
left to review.
</p>

<p>
As library clauses continue to be deprecated and migrate to Annex D, use of
this deprecated convention will become internally less consistent, so the
strong recommendation is to apply the new tags consistently through the parts
of Annex D that are retained.  The weak recommendation is to let this term
remain until the last clause using it has been removed (or undeprecated and
updated) in a future standard.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this feature from C++23.
</blockquote>


<blockquote class="draft_wording">
<h4><del>D.10 Requires paragraph [depr.res.on.required]</del></h4>
<ol>
<li><del>
In addition to the elements specified in 16.4.1.4, descriptions of function
semantics may also contain a <i>Requires:</i> element to denote the
preconditions for calling a function.
</del></li>
<li><del>
Violation of any preconditions specified in a function's <i>Requires:</i>
element results in undefined behavior unless the function's <i>Throws:</i>
element specifies throwing an exception when the precondition is violated.
</del></li>
</ol>
</blockquote>

<blockquote class="old_wording">
<h4>D.11 Relational operators [depr.relops] </h4>
<blockquote class="note">
The <i>Cpp17OldConcept</i> requirements contain a semantic component, so the
most appropriate replacement for a <i>Requires</i> clause is a
<i>Preconditions</i> clause.
</blockquote>
<ol>
<li>
The header <code>&lt;utility&gt;</code> (20.2.1) has the following additions:
</li>

<blockquote><pre>
namespace std::rel_ops {
  template&lt;class T&gt; bool operator!=(const T&amp;, const T&amp;);
  template&lt;class T&gt; bool operator&gt; (const T&amp;, const T&amp;);
  template&lt;class T&gt; bool operator&lt;=(const T&amp;, const T&amp;);
  template&lt;class T&gt; bool operator&gt;=(const T&amp;, const T&amp;);
}
</pre></blockquote>
<li>
To avoid redundant definitions of <code>operator!=</code> out of
<code>operator==</code> and operators <code>&gt;</code>, <code>&lt;=</code>,
and <code>&gt;=</code> out of <code>operator&lt;</code>, the library provides
the following:
</li>

<pre>template&lt;class T&gt; bool operator!=(const T&amp; x, const T&amp; y);</pre>
<li>
<del><i>Requires:</i> Type <code>T</code> is <i>Cpp17EqualityComparable</i> (Table 25).</del>
<ins><i>Preconditions:</i> <code>T</code> meets the <i>Cpp17EqualityComparable</i> requirements (Table 25).</ins>
</li>
<li>
<i>Returns:</i> <code>!(x == y)</code>.
</li>

<pre>template&lt;class T&gt; bool operator&gt;(const T&amp; x, const T&amp; y);</pre>
<li>
<del><i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 26).</del>
<ins><i>Preconditions:</i> <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 26).</ins>
</li>
<li>
<i>Returns:</i> <code>y &lt; x</code>.
</li>

<pre>template&lt;class T&gt; bool operator&lt;=(const T&amp; x, const T&amp; y);</pre>
<li>
<del><i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 26).</del>
<ins><i>Preconditions:</i> <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 26).</ins>
</li>
<li>
<i>Returns:</i> <code>!(y &lt; x)</code>.
</li>

<pre>template&lt;class T&gt; bool operator&gt;=(const T&amp; x, const T&amp; y);</pre>
<li>
<del><i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 26).</del>
<ins><i>Preconditions:</i> <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 26).</ins>
</li>
<li>
<i>Returns:</i> <code>!(x &lt; y)</code>.
</li>
</ol>

<h4>D.13 Deprecated type traits [depr.meta.types]</h4>
<ol>
<li>
The header <code>&lt;type_traits&gt;</code> (20.15.2) has the following additions:
</li>
<blockquote><pre>
namespace std {
  template&lt;class T&gt; struct is_pod;
  template&lt;class T&gt; inline constexpr bool is_pod_v = is_pod&lt;T&gt;::value;
}
</pre></blockquote>

<li>
The behavior of a program that adds specializations for any of the templates
defined in this subclause is undefined, unless explicitly permitted by the
specification of the corresponding template.
</li>

<pre>template&lt;class T&gt; struct is_pod;</pre>
<li>
<i><del>Requires</del><ins>Mandates</ins>:</i>
<code>remove_all_extents_t&lt;T&gt;</code> shall be a complete type or
<i>cv</i> <code>void</code>.
</li>

<li>
<i><ins>Remarks:</ins></i>
<code>is_pod&lt;T&gt;</code> is a <i>Cpp17UnaryTypeTrait</i> (20.15.1) with a
base characteristic of <code>true_type</code> if <code>T</code> is a POD type,
and <code>false_type</code> otherwise. A POD class is a class that is both a
trivial class and a standard-layout class, and has no non-static data members
of type non-POD class (or array thereof). A POD type is a scalar type, a POD
class, an array of such a type, or a cv-qualified version of one of these
types.
</li>

<li>
[<i>Note:</i> It is unspecified whether a closure type (7.5.5.1) is a POD type.
<i>&mdash;end note</i>]
</li>
</ol>
</blockquote>


<blockquote class="draft_wording">
<h4>D.18 Deprecated <code>shared_ptr</code> atomic access [depr.util.smartptr.shared.atomic]</h4>
<ol>
<li>
The header <code>&lt;memory&gt;</code>  (20.10.2) has the following additions:
</li>

<blockquote><pre>
namespace std {
template &lt;class T&gt;
  bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);

template &lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);
template &lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);

template &lt;class T&gt;
  void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);
template &lt;class T&gt;
  void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);

template &lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);
template &lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);

template &lt;class T&gt;
  bool atomic_compare_exchange_weak(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);
template &lt;class T&gt;
  bool atomic_compare_exchange_strong(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);
template &lt;class T&gt;
  bool atomic_compare_exchange_weak_explicit(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,
    memory_order success, memory_order failure);
template &lt;class T&gt;
  bool atomic_compare_exchange_strong_explicit(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,
    memory_order success, memory_order failure);
}
</pre></blockquote>

<li>
Concurrent access to a <code>shared_ptr</code> object from multiple threads
does not introduce a data race if the access is done exclusively via the
functions in this section and the instance is passed as their first argument.
</li>
<li>
The meaning of the arguments of type <code>memory_order</code> is explained in
31.4.
</li>

<blockquote><pre>
template&lt;class T&gt;
  bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Returns:</i> <code>true</code> if atomic access to <code>*p</code> is
lock-free, <code>false</code> otherwise.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Returns:</i> <code>atomic_load_explicit(p, memory_order::seq_cst)</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>mo</code> <del>shall
not be</del><ins>is neither</ins> <code>memory_order::release</code>
<ins>n</ins>or <code>memory_order::acq_rel</code>.
</li>
<li>
<i>Returns:</i> <code>*p</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Effects:</i> As if by
<code>atomic_store_explicit(p, r, memory_order::seq_cst)</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Requires:</i> <code>mo</code> shall not be
<code>memory_order::acquire</code> or <code>memory_order::acq_rel</code>.
</li>
<li>
<i>Effects:</i> As if by <code>p-&gt;swap(r)</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Returns:</i> <code>atomic_exchange_explicit(p, r, memory_order::seq_cst)</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Effects:</i> As if by <code>p-&gt;swap(r)</code>.
</li>
<li>
<i>Returns:</i> The previous value of <code>*p</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  bool atomic_compare_exchange_weak(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> null.
</li>
<li>
<i>Returns:</i>
<code>atomic_compare_exchange_weak_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)</code>.
</li>
<li>
<i>Throws:</i> Nothing.
</li>

<blockquote><pre>
template&lt;class T&gt;
  bool atomic_compare_exchange_strong(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);
</pre></blockquote>
<li>
<i>Returns:</i>
<code>atomic_compare_exchange_strong_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)</code>.
</li>

<blockquote><pre>
template &lt;class T&gt;
  bool atomic_compare_exchange_weak_explicit(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,
    memory_order success, memory_order failure);
template &lt;class T&gt;
  bool atomic_compare_exchange_strong_explicit(
    shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,
    memory_order success, memory_order failure);
</pre></blockquote>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>p</code> <del>shall
not be</del><ins>is not</ins> and <code>v</code> <del>shall not be</del><ins>is
not</ins> null.  The <code>failure</code> argument <del>shall not
be</del><ins>is neither</ins> <code>memory_order::release</code> nor
<code>memory_order::acq_rel</code>.
</li>
<li>
<i>Effects:</i> If <code>*p</code> is equivalent to <code>*v</code>, assigns
<code>w</code> to <code>*p</code> and has synchronization semantics
corresponding to the value of <code>success</code>, otherwise assigns
<code>*p</code> to <code>*v</code> and has synchronization semantics
corresponding to the value of <code>failure</code>.
</li>
<li>
<i>Returns:</i> <code>true</code> if <code>*p</code> was equivalent to
<code>*v</code>, <code>false</code> otherwise.
</li>
<li>
<i>Throws:</i> Nothing.
</li>
<li>
<i>Remarks:</i> Two <code>shared_ptr</code> objects are equivalent if they
store the same pointer value and share ownership. The weak form may fail
spuriously.  See 31.8.1.
</li>
</ol>


<h4>D.21 Deprecated convenience conversion interfaces [depr.conversions]</h4>
<h4>D.21.1 Class template wstring_convert [depr.conversions.string]</h4>
<ol>
<li>
Class template <code>wstring_convert</code> performs conversions between a wide
string and a byte string.  It lets you specify a code conversion facet (like
class template <code>codecvt</code>) to perform the conversions, without
affecting any streams or locales.  [ <i>Example:</i> If you want to use the
code conversion facet <code>codecvt_utf8</code> to output to <code>cout</code>
a UTF-8 multibyte sequence corresponding to a wide string, but you don’t want
to alter the locale for <code>cout</code>, you can write something like:
<blockquote><pre>
<ins>std::</ins>wstring_convert&lt;std::codecvt_utf8&lt;wchar_t&gt;&gt; myconv;
std::string mbstring = myconv.to_bytes(L"Hello\n");
std::cout &lt;&lt; mbstring;
</pre></blockquote>
&mdash; <i>end example</i> ]
</li>

<pre><blockquote>
namespace std {
template &lt;class Codecvt, class Elem = wchar_t,
          class WideAlloc = allocator&lt;Elem&gt;,
          class ByteAlloc = allocator&lt;char&gt;&gt;
  class wstring_convert {
  public:
    using byte_string = basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;;
    using wide_string = basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;;
    using state_type  = typename Codecvt::state_type;
    using int_type    = typename wide_string::traits_type::int_type;

    wstring_convert() : wstring_convert(new Codecvt) {}
    explicit wstring_convert(Codecvt* pcvt = new Codecvt);
    wstring_convert(Codecvt* pcvt, state_type state);
    explicit wstring_convert(const byte_string&amp; byte_err,
                             const wide_string&amp; wide_err = wide_string());
    ~wstring_convert();

    wstring_convert(const wstring_convert&amp;) = delete;
    wstring_convert&amp; operator=(const wstring_convert&amp;) = delete;

    wide_string from_bytes(char byte);
    wide_string from_bytes(const char* ptr);
    wide_string from_bytes(const byte_string&amp; str);
    wide_string from_bytes(const char* first, const char* last);

    byte_string to_bytes(Elem wchar);
    byte_string to_bytes(const Elem* wptr);
    byte_string to_bytes(const wide_string&amp; wstr);
    byte_string to_bytes(const Elem* first, const Elem* last);

    size_t converted() const noexcept;
    state_type state() const;

  private:
    byte_string byte_err_string;  <i>// Exposition only</i>
    wide_string wide_err_string;  <i>// Exposition only</i>
    Codecvt* cvtptr;              <i>// Exposition only</i>
    state_type cvtstate;          <i>// Exposition only</i>
    size_t cvtcount;              <i>// Exposition only</i>
  };
}
</blockquote></pre>

<li>
The class template describes an object that controls conversions between wide
string objects of class
<code>basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;</code> and
byte string objects of class
<code>basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;</code>.
The class template defines the types <code>wide_string</code> and
<code>byte_string</code> as synonyms for these two types. Conversion between a
sequence of <code>Elem</code> values (stored in a <code>wide_string</code>
object) and multibyte sequences (stored in a <code>byte_string</code> object)
is performed by an object of class <code>Codecvt</code>, which meets the
requirements of the standard code-conversion facet
<code>codecvt&lt;Elem, char, mbstate_t&gt;</code>.
</li>
<li>
An object of this class template stores:
  <ol>
  <li>
  &mdash; <code>byte_err_string</code> &mdash; a byte string to display on errors
  </li>
  <li>
  &mdash; <code>wide_err_string</code> &mdash; a wide string to display on errors
  </li>
  <li>
  &mdash; <code>cvtptr</code> &mdash; a pointer to the allocated conversion object
  (which is freed when the <code>wstring_convert</code> object is destroyed)
  </li>
  <li>
  &mdash; <code>cvtstate</code> &mdash; a conversion state object
  </li>
  <li>
  &mdash; <code>cvtcount</code> &mdash; a conversion count
  </li>
  </ol>
</li>

<pre><blockquote>
using byte_string = basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;;
</blockquote></pre>
<li>
The type shall be a synonym for
<code>basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;</code>
</li>

<pre><blockquote>
size_t converted() const noexcept;
</blockquote></pre>
<li>
<i>Returns:</i> <code>cvtcount</code>.
</li>

<pre><blockquote>
wide_string from_bytes(char byte);
wide_string from_bytes(const char* ptr);
wide_string from_bytes(const byte_string&amp; str);
wide_string from_bytes(const char* first, const char* last);
</blockquote></pre>
<li>
<i>Effects:</i> The first member function shall convert the single-element
sequence <code>byte</code> to a wide string. The second member function shall
convert the null-terminated sequence beginning at <code>ptr</code> to a wide
string. The third member function shall convert the sequence stored in str to a
wide string. The fourth member function shall convert the sequence defined by
the range <code>[first, last)</code> to a wide string.
</li>
<li>
In all cases:
  <ol>
  <li>
&mdash; If the <code>cvtstate</code> object was not constructed with an
explicit value, it shall be set to its default value (the initial conversion
state) before the conversion begins. Otherwise it shall be left unchanged.
  </li>
  <li>
&mdash; The number of input elements successfully converted shall be stored in
<code>cvtcount</code>.
  </li>
  </ol>
</li>

<li>
<i>Returns:</i> If no conversion error occurs, the member function shall return
the converted wide string. Otherwise, if the object was constructed with a
wide-error string, the member function shall return the wide-error string.
Otherwise, the member function throws an object of class
<code>range_error</code>.
</li>

<pre><blockquote>
using int_type = typename wide_string::traits_type::int_type;
</blockquote></pre>
<li>
The type shall be a synonym for <code>wide_string::traits_type::int_type</code>.
</li>

<pre><blockquote>
state_type state() const;
</blockquote></pre>
<li>
returns <code>cvtstate</code>.
</li>

<pre><blockquote>
using state_type = typename Codecvt::state_type;
</blockquote></pre>
<li>
The type shall be a synonym for <code>Codecvt::state_type</code>.
</li>

<pre><blockquote>
byte_string to_bytes(Elem wchar);
byte_string to_bytes(const Elem* wptr);
byte_string to_bytes(const wide_string&amp; wstr);
byte_string to_bytes(const Elem* first, const Elem* last);
</blockquote></pre>
<li>
<i>Effects:</i> The first member function shall convert the single-element
sequence <code>wchar</code> to a byte string. The second member function shall
convert the null-terminated sequence beginning at <code>wptr</code> to a byte
string. The third member function shall convert the sequence stored in wstr to
a byte string. The fourth member function shall convert the sequence defined by
the range <code>[first, last)</code> to a byte string.
</li>

<li>
In all cases:
  <ol>
  <li>
&mdash; If the <code>cvtstate</code> object was not constructed with an
explicit value, it shall be set to its default value (the initial conversion
state) before the conversion begins. Otherwise it shall be left unchanged.
  </li>
  <li>
&mdash; The number of input elements successfully converted shall be stored in
<code>cvtcount</code>.
  </li>
  </ol>
</li>

<li>
<i>Returns:</i> If no conversion error occurs, the member function shall return
the converted byte string. Otherwise, if the object was constructed with a
byte-error string, the member function shall return the byte-error string.
Otherwise, the member function shall throw an object of class
<code>range_error</code>.
</li>

<pre><blockquote>
using wide_string = basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;;
</blockquote></pre>
<li>
The type shall be a synonym for
<code>basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;</code>.
</li>

<pre><blockquote>
explicit wstring_convert(Codecvt* pcvt = new Codecvt);
wstring_convert(Codecvt* pcvt, state_type state);
explicit wstring_convert(const byte_string&amp; byte_err,
    const wide_string&amp; wide_err = wide_string());
</blockquote></pre>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> For the first and second constructors, <code>pcvt != nullptr</code>.
</li>

<li>
<i>Effects:</i> The first constructor shall store <code>pcvt</code> in
<code>cvtptr</code> and default values in <code>cvtstate</code>,
<code>byte_err_string</code>, and <code>wide_err_string</code>. The second
constructor shall store <code>pcvt</code> in <code>cvtptr</code>,
<code>state</code> in <code>cvtstate</code>, and default values in
<code>byte_err_string</code> and <code>wide_err_string</code>; moreover the
stored state shall be retained between calls to <code>from_bytes</code> and
<code>to_bytes</code>. The third constructor shall store
<code>new Codecvt</code> in <code>cvtptr</code>, <code>state_type()</code> in
<code>cvtstate</code>, <code>byte_err</code> in <code>byte_err_string</code>,
and <code>wide_err</code> in <code>wide_err_string</code>.
</li>

<pre><blockquote>
~wstring_convert();
</blockquote></pre>
<li>
<i>Effects:</i> The destructor shall delete <code>cvtptr</code>.
</li>
</ol>


<h4>D.21.2 Class template wbuffer_convert [depr.conversions.buffer]</h4>
<ol>
<li>
Class template <code>wbuffer_convert</code> looks like a wide stream buffer,
but performs all its I/O through an underlying byte stream buffer that you
specify when you construct it. Like class template
<code>wstring_convert</code>, it lets you specify a code conversion facet to
perform the conversions, without affecting any streams or locales.
</li>
<pre><blockquote>
namespace std {
template &lt;class Codecvt, class Elem = wchar_t, class Tr = char_traits&lt;Elem&gt;&gt;
  class wbuffer_convert
    : public basic_streambuf&lt;Elem, Tr&gt; {
  public:
    using state_type = typename Codecvt::state_type;

    wbuffer_convert() : wbuffer_convert(nullptr) {}
    explicit wbuffer_convert(streambuf* bytebuf = 0,
                             Codecvt* pcvt = new Codecvt,
                             state_type state = state_type());

    ~wbuffer_convert();

    wbuffer_convert(const wbuffer_convert&amp;) = delete;
    wbuffer_convert&amp; operator=(const wbuffer_convert&amp;) = delete;

    streambuf* rdbuf() const;
    streambuf* rdbuf(streambuf* bytebuf);

    state_type state() const;

  private:
    streambuf* bufptr;        // exposition only
    Codecvt* cvtptr;          // exposition only
    state_type cvtstate;      // exposition only
  };
}
</blockquote></pre>
<li>
The class template describes a stream buffer that controls the transmission of
elements of type <code>Elem</code>, whose character traits are described by the
class <code>Tr</code>, to and from a byte stream buffer of type
<code>streambuf</code>.  Conversion between a sequence of <code>Elem</code>
values and multibyte sequences is performed by an object of class
<code>Codecvt</code>, which shall meet the requirements of the standard
code-conversion facet <code>codecvt&lt;Elem, char, mbstate_t&gt;</code>.
</li>

<li>
An object of this class template stores:
  <ol>
  <li>
&mdash; <code>bufptr</code> &mdash; a pointer to its underlying byte stream buffer
  </li>
  <li>
&mdash; <code>cvtptr</code> &mdash; a pointer to the allocated conversion
object (which is freed when the <code>wbuffer_convert</code> object is
destroyed)
  </li>
  <li>
&mdash; <code>cvtstate</code> &mdash; a conversion state object
  </li>
  </ol>
</li>

<pre><blockquote>
state_type state() const;
</blockquote></pre>
<li>
<i>Returns:</i> <code>cvtstate</code>.
</li>

<pre><blockquote>
streambuf* rdbuf() const;
</blockquote></pre>
<li>
<i>Returns:</i> <code>bufptr</code>.
</li>

<pre><blockquote>
streambuf* rdbuf(streambuf* bytebuf);
</blockquote></pre>
<li>
<i>Effects:</i> Stores <code>bytebuf</code> in <code>bufptr</code>.
</li>
<li>
<i>Returns:</i> The previous value of <code>bufptr</code>.
</li>

<pre><blockquote>
using state_type = typename Codecvt::state_type;
</blockquote></pre>
<li>
The type shall be a synonym for <code>Codecvt::state_type</code>.
</li>

<pre><blockquote>
explicit wbuffer_convert(streambuf* bytebuf = 0,
    Codecvt* pcvt = new Codecvt, state_type state = state_type());
</blockquote></pre>
<li>
<i><del>Requires</del><ins>Preconditions</ins>:</i> <code>pcvt != nullptr</code>.
</li>
<li>
<i>Effects:</i> The constructor constructs a stream buffer object, initializes
<code>bufptr</code> to <code>bytebuf</code>, initializes <code>cvtptr</code> to
<code>pcvt</code>, and initializes <code>cvtstate</code> to <code>state</code>.
</li>

<pre><blockquote>
~wbuffer_convert();
</blockquote></pre>

<li>
<i>Effects:</i> The destructor shall delete <code>cvtptr</code>.
</li>
</ol>


<h4>D.23 Deprecated filesystem path factory functions [depr.fs.path.factory]</h4>
<blockquote class="note">
The <i>Requires</i> clause here covers both compile-time and run-time
conditions, so is split into separate <i>Mandates</i> and <i>Preconditions</i>
clauses.  A drive-by fix further catches that several typedefs intending to
refer to members of <code>path</code> are actually meaningless for a non-member
factory function.  The current form of wording was copy/pasted from the
specification of constructors where the <code>path::</code> would be implicit.
</blockquote>
<ol>
<li><ins>
The header <code>&lt;filesystem&gt;</code> (29.11.5) has the following additions:
</ins></li>
<pre>
template&lt;class Source&gt;
  path u8path(const Source&amp; source);
template&lt;class InputIterator&gt;
  path u8path(InputIterator first, InputIterator last);
</pre>

<li><del>
<i>Requires:</i> The <code>source</code> and <code>[first, last)</code>
sequences are UTF-8 encoded. The value type of <code>Source</code> and
<code>InputIterator</code> is <code>char</code> or <code>char8_t</code>.
<code>Source</code> meets the requirements specified in 29.11.7.3.
</del></li>

<li><ins>
<i>Mandates:</i> The value type of <code>Source</code> and
<code>InputIterator</code> is <code>char</code> or
<code>char8_t</code>.
</ins></li>
<li><ins>
<i>Preconditions:</i> The <code>source</code> and <code>[first, last)</code>
sequences are UTF-8 encoded.   <code>Source</code> meets the requirements
specified in 29.11.7.3.
</ins></li>

<li>
<i>Returns:</i>
<ol>
<li>
&mdash; If <code><ins>path::</ins>value_type</code> is <code>char</code> and
the current native narrow encoding (29.11.7.2.2) is UTF-8, return
<code>path(source)</code> or <code>path(first, last)</code>; otherwise,
</li>
<li>
&mdash; if <code><ins>path::</ins>value_type</code> is <code>wchar_t</code> and
the native wide encoding is UTF-16, or if
<code><ins>path::</ins>value_type</code> is <code>char16_t</code> or
<code>char32_t</code>, convert <code>source</code> or <code>[first,last)</code>
to a temporary, <code>tmp</code>, of type
<code><ins>path::</ins>string_type</code> and return <code>path(tmp)</code>;
otherwise,
</li>
<li>
&mdash; convert <code>source</code> or <code>[first, last)</code> to a
temporary, <code>tmp</code>, of type <code>u32string</code> and return
<code>path(tmp)</code>.
</li>
</ol>
<li>
<i>Remarks:</i> Argument format conversion (29.11.7.2.1) applies to the
arguments for these functions. How Unicode encoding conversions are performed
is unspecified.
</li>
<li>
[<i>Example:</i> A string is to be read from a database that is encoded in
UTF-8, and used to create a directory using the native encoding for filenames:
<blockquote><pre>
namespace fs = std::filesystem;
std::string utf8_string = read_utf8_data();
fs::create_directory(fs::u8path(utf8_string));
</pre></blockquote>
For POSIX-based operating systems with the native narrow encoding set to UTF-8,
no encoding or type conversion occurs.
<p>
For POSIX-based operating systems with the native narrow encoding not set to
UTF-8, a conversion to UTF-32 occurs, followed by a conversion to the current
native narrow encoding. Some Unicode characters may have no native character
set representation.
</p>
For Windows-based operating systems a conversion from UTF-8 to UTF-16 occurs.
<i>&mdash;end example</i>] [<i>Note:</i> The example above is representative of
a historical use of <code>filesystem::u8path</code>. Passing a
<code>std::u8string</code> to <code>path</code>’s constructor is preferred for
an indication of UTF-8 encoding more consistent with <code>path</code>’s
handling of other encodings. <i>&mdash;end note</i>]
</li>
</ol>

</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="review">
<b>LEWGI Review:</b>
Defer to LWG
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.11">Relational operators [depr.relops]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was deprecated with the introduction of support for the 3-way
comparison &quot;spaceship&quot; operator, by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0768r1">P0768R1</a>.
</p>

<p>
The <code>std::rel_ops</code> namespace was introduced in the original C++
standard, so its removal would potentially impact on code written against C++98
and later standards.  However, this paper will still recommend strongly for its
removal from the C++23 standard.  The feature relies on the antipattern of
<code>using</code> a namespace in a namespace scope in order to provide
comparison operators for my own type, typically in a header.  Such usage is not
recommended as the <code>using</code> will have an impact on code in other
headers, and potentially introduce header order dependencies.  A more targeted
use within a function may serve as an adaption for 3rd party libraries, but
again, by providing these operators for all types whether desired or not.  As
there are no viable base classes in this namespace, it was never possible to
arrange for these operators to be discovered by ADL, so there was no better
workaround to tame these functions.
</p>
<p>
The better solution appeared in C++20 with the introduction of the spaceship
operator, and rules for synthesizing comparisons from a few primitive operators
now built into the language.  The typical remedy for much code will be to
simply remove the offending <code>using namespace std::rel_ops;</code> from
their code, and it should continue to work.  As added insurance, the name
<code>rel_ops</code> will be added to the list of zombie names reserved for
previous standardization so that standard library vendors can continue to offer
these as a compatibility shim for their customers for as long as they wish, so
the impact on the user community of removing the specification of this feature
from the standard is expected to be minimal.
</p>

<p>
The weak recommendation is that this feature was deprecated just one standard
prior, so the user community may take a while to catch up and remove the
dependencies from their code.  Holding the feature in Annex D does little harm,
but the wording should be updated to the latest library documentation style for
C++23.  We do not see any reason to consider undeprecation of this feature.
</p>

<p>
As a historical note, the standard library specification itself used to rely on
<code>std::rel_ops</code> to provide the specification for any comparison
operator if the necessary wording were missing.  However, as part of C++20, it
was confirmed that no current wording relies on that legacy fall-back, and the
corresponding as-if wording has already been removed.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this feature from C++23.
</blockquote>


<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li><ins>&mdash; <code>rel_ops</code>,</ins></li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>, and</li>
<li>&mdash; <code>unexpected_handler</code>.</li>
</ol></li>
</ol>

<h4><del>D.11 Relational operators [depr.relops] </del></h4>
<ol>
<li><del>
The header <code>&lt;utility&gt;</code> (20.2.1) has the following additions:
</del></li>

<blockquote><pre>
<del>>namespace std::rel_ops {</del>
  <del>template&lt;class T&gt; bool operator!=(const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&gt; (const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&lt;=(const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&gt;=(const T&amp;, const T&amp;);</del>
<del>>}</del>
</pre></blockquote>
<li><del>
To avoid redundant definitions of <code>operator!=</code> out of
<code>operator==</code> and operators <code>&gt;</code>, <code>&lt;=</code>, and
<code>&gt;=</code> out of <code>operator&lt;</code>, the library provides the
following:
</del></li>

<pre><del>template&lt;class T&gt; bool operator!=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17EqualityComparable</i> (Table 23).
</del></li>
<li><del>
<i>Returns:</i> <code>!(x == y)</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&gt;(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>y &lt; x</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&lt;=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>!(y &lt; x)</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&gt;=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>!(x &lt; y)</code>.
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Clean up wording.
</blockquote>

<blockquote class="note">
Update wording to replace <i>Requires</i> clauses (see <a href="#3.10">D.10 Requires paragraph</a>).
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Concerns were raised about the lack of research into how much code is likely to
break with the removal of this API.  We would like to see more numbers and
analysis on publicly available code, such as across all of Github.  Given that
implementers are likely to provide an implementation (through zombie names
freedom) for some time after removal, there was consensus to proceed with
removal, assuming the requested research does not reveal major concerns before
the main LEWG review to follow.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23.
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.12"><code>char*</code> streams [depr.str.strstreams]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++98
</blockquote>

<p>
The <code>char*</code> streams were provided, pre-deprecated, in C++98 and have
been considered for removal before.  The underlying principle of not removing
them until a suitable replacement is available still holds, so there should be
nothing further to discuss at this point.
</p>
<p>
However, it should be noted that the <code>spanstream</code> library
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0448r2">P0448R2</a>)
passed LEWG review for C++20, but ran out of LWG working time to integrate into
the final standard.  This library is expected to be the replacement facility we
point users to in the future, so it may be reasonable to again consider the
classic strstreams facility for removal in C++26.
</p>
<p>
There remains the alternative position that this facility has been a supported
shipping part of the C++ standard for around 25 years when C++23 ships.  If we
have not made serious moves to remove the library in all that time, maybe we
should consider undeprecating, and taking away the shadow of doubt over any
code that reaches for this facility today.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Undeprecate the <code>char*</code> streams.
</blockquote>

<blockquote class="note">
Text moved and renumbered without any review to modernising the wording.  Do
observe that the paragraph types are consistent with current library practice
though, so we do not need a &quot;mandates review&quot;.
</blockquote>

<blockquote class="draft_wording">
<h4><ins>29.11 <code>char*</code> streams [str.strstreams]</ins></h4>
<h4><ins>29.11.1 Header <code>&lt;strstream&gt;</code> synopsis [strstream.syn]</ins></h4>
<ol>
<li><ins>
The header <code>&lt;strstream&gt;</code> defines types that associate stream
buffers with character array objects and assist reading and writing such
objects.
</ins></li>
</ol>
<blockquote class="note">
Could use a better description indicating how these stream classes are distinct
from the <code>stringstream</code> classes.
</blockquote>

<blockquote><pre><ins>
namespace std {
  class strstreambuf;
  class istrstream;
  class ostrstream;
  class strstream;
}
</ins></pre></blockquote>

<h4><ins>29.11.2 Class <code>strstreambuf</code> [strstreambuf]</ins></h4>
<blockquote><pre><ins>
namespace std {
  class strstreambuf : public basic_streambuf&lt;char&gt; {
  public:
    strstreambuf() : strstreambuf(0) {}
    explicit strstreambuf(streamsize alsize_arg);
    strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));
    strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr);
    strstreambuf(const char* gnext_arg, streamsize n);

    strstreambuf(signed char* gnext_arg, streamsize n,
                 signed char* pbeg_arg = nullptr);
    strstreambuf(const signed char* gnext_arg, streamsize n);
    strstreambuf(unsigned char* gnext_arg, streamsize n,
                 unsigned char* pbeg_arg = nullptr);
    strstreambuf(const unsigned char* gnext_arg, streamsize n);

    virtual ~strstreambuf();

    void  freeze(bool freezefl = true);
    char* str();
    int   pcount();

  protected:
    int_type overflow (int_type c = EOF) override;
    int_type pbackfail(int_type c = EOF) override;
    int_type underflow() override;
    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    streambuf* setbuf(char* s, streamsize n) override;

  private:
    using strstate = T1;               <i>// exposition only</i>
    static const strstate allocated;   <i>// exposition only</i>
    static const strstate constant;    <i>// exposition only</i>
    static const strstate dynamic;     <i>// exposition only</i>
    static const strstate frozen;      <i>// exposition only</i>
    strstate strmode;                  <i>// exposition only</i>
    streamsize alsize;                 <i>// exposition only</i>
    void* (*palloc)(size_t);           <i>// exposition only</i>
    void (*pfree)(void*);              <i>// exposition only</i>
  };
}
</ins></pre></blockquote>

<ol>
<li><ins>
The class <code>strstreambuf</code> associates the input sequence, and possibly
the output sequence, with an object of some character array type, whose
elements store arbitrary values. The array object has several attributes.
</ins></li>
<li><ins>
[<i>Note:</i> For the sake of exposition, these are represented as elements of
a bitmask type (indicated here as <code>T1</code>) called
<code>strstate</code>. The elements are:
  <ol>
  <li><ins>
&mdash; <code>allocated</code>, set when a dynamic array object has been
allocated, and hence should be freed by the destructor for the
<code>strstreambuf</code> object;
  </ins></li>
  <li><ins>
&mdash; <code>constant</code>, set when the array object has
<code>const</code> elements, so the output sequence cannot be written;
  </ins></li>
  <li><ins>
&mdash; <code>dynamic</code>, set when the array object is allocated (or
reallocated) as necessary to hold a character sequence that can change in
length;
  </ins></li>
  <li><ins>
&mdash; <code>frozen</code>, set when the program has requested that the array
object not be altered, reallocated, or freed.
  </ins></li>
  </ol>
<i>&mdash;end note</i>]
</ins></li>
<li><ins>
[<i>Note:</i> For the sake of exposition, the maintained data is presented here
as:
  <ol>
  <li><ins>
&mdash; <code>strstate strmode</code>, the attributes of the array object
associated with the <code>strstreambuf</code> object;
  </ins></li>
  <li><ins>
&mdash; <code>int alsize</code>, the suggested minimum size for a dynamic array
object;
  </ins></li>
  <li><ins>
&mdash; <code>void* (*palloc)(size_t)</code>, points to the function to call to
allocate a dynamic array object;
  </ins></li>
  <li><ins>
&mdash; <code>void (*pfree)(void*)</code>, points to the function to call to
free a dynamic array object.
  </ins></li>
  </ol>
<i>&mdash;end note</i>]
</ins></li>
<li><ins>
Each object of class <code>strstreambuf</code> has a seekable area, delimited
by the pointers <code>seeklow</code> and <code>seekhigh</code>. If
<code>gnext</code> is a null pointer, the seekable area is undefined.
Otherwise, <code>seeklow</code> equals <code>gbeg</code> and
<code>seekhigh</code> is either <code>pend</code>, if <code>pend</code> is not
a null pointer, or <code>gend</code>.
</ins></li>
</ol>

<h4><ins>29.11.2.1 <code>strstreambuf</code> constructors [strstreambuf.cons]</ins></h4>
<ol>
<pre><ins>explicit strstreambuf(streamsize alsize_arg);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 148.
</ins></li>
</ol>

<table align="center">
<caption><ins>
Table 148: <code>strstreambuf(streamsize)</code> effects
[tab:depr.strstreambuf.cons.sz]
</ins></caption>
<tr>
  <th><ins>Element</ins></th>
  <th><ins>Value</ins></th>
</tr>
<tr>
  <td><ins><code>strmode</code></ins></td>
  <td><ins><code>dynamic</code></ins></td>
</tr>
<tr>
  <td><ins><code>alsize</code></ins></td>
  <td><ins><code>alsize_arg</code></ins></td>
</tr>
<tr>
  <td><ins><code>palloc</code></ins></td>
  <td><ins>a null pointer</ins></td>
</tr>
<tr>
  <td><ins><code>pfree</code></ins></td>
  <td><ins>a null pointer</ins></td>
</tr>
</table>

<ol start="2">
<pre><ins>strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 149.
</ins></li>
</ol>
<table align="center">
<caption><ins>
Table 149: <code>strstreambuf(void* (*)(size_t), void (*)(void*))</code> effects
[tab:depr.strstreambuf.cons.alloc]
</ins></caption>
<tr>
  <th><ins>Element</ins></th>
  <th><ins>Value</ins></th>
</tr>
<tr>
  <td><ins><code>strmode</code></ins></td>
  <td><ins><code>dynamic</code></ins></td>
</tr>
<tr>
  <td><ins><code>alsize</code></ins></td>
  <td><ins>an unspecified value</ins></td>
</tr>
<tr>
  <td><ins><code>palloc</code></ins></td>
  <td><ins><code>palloc_arg</code></ins></td>
</tr>
<tr>
  <td><ins><code>pfree</code></ins></td>
  <td><ins><code>pfree_arg</code></ins></td>
</tr>
</table>

<ol start="3">
<pre><ins>strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr);
strstreambuf(signed char* gnext_arg, streamsize n,
             signed char* pbeg_arg = nullptr);
strstreambuf(unsigned char* gnext_arg, streamsize n,
             unsigned char* pbeg_arg = nullptr);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 150.
</ins></li>
</ol>

<table align="center">
<caption><ins>
Table 150: <code>strstreambuf(charT*, streamsize, charT*)</code> effects
[tab:depr.strstreambuf.cons.ptr]
</ins></caption>
<tr>
  <th><ins>Element</ins></th>
  <th><ins>Value</ins></th>
</tr>
<tr>
  <td><ins><code>strmode</code></ins></td>
  <td><ins>0</ins></td>
</tr>
<tr>
  <td><ins><code>alsize</code></ins></td>
  <td><ins>an unspecified value</ins></td>
</tr>
<tr>
  <td><ins><code>palloc</code></ins></td>
  <td><ins>a null pointer</ins></td>
</tr>
<tr>
  <td><ins><code>pfree</code></ins></td>
  <td><ins>a null pointer</ins></td>
</tr>
</table>

<ol start="4">
<li><ins>
<code>gnext_arg</code> shall point to the first element of an array object
whose number of elements <code>N</code> is determined as follows:
  <ol>
  <li><ins>
&mdash; If <code>n &gt; 0</code>, <code>N</code> is <code>n</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>n == 0</code>, <code>N</code> is <code>std::strlen(gnext_arg)</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>n &lt; 0</code>, <code>N</code> is <code>INT_MAX</code>.<sup>327</sup>
  </ins></li>
  </ol>
</ins></li>

<li><ins>
If <code>pbeg_arg</code> is a null pointer, the function executes:
<blockquote><pre><ins>setg(gnext_arg, gnext_arg, gnext_arg + N);</ins></pre></blockquote>
</ins></li>
<li><ins>
Otherwise, the function executes:
<blockquote><pre><ins>setg(gnext_arg, gnext_arg, pbeg_arg);
setp(pbeg_arg,  pbeg_arg + N);</ins></pre></blockquote>
</ins></li>

<pre><ins>strstreambuf(const char* gnext_arg, streamsize n);
strstreambuf(const signed char* gnext_arg, streamsize n);
strstreambuf(const unsigned char* gnext_arg, streamsize n);</ins></pre>
<li><ins>
<i>Effects:</i> Behaves the same as
<code>strstreambuf((char*)gnext_arg,n)</code>, except that the constructor also
sets <code>constant</code> in <code>strmode</code>.
</ins></li>

<pre><ins>virtual ~strstreambuf();</ins></pre>
<li><ins>
<i>Effects:</i> Destroys an object of class <code>strstreambuf</code>. The
function frees the dynamically allocated array object only if <code>(strmode
&amp; allocated) != 0</code> and <code>(strmode &amp; frozen) == 0</code>.
(29.11.2.3 describes how a dynamically allocated array object is freed.)
</ins></li>
</ol>

<h4><ins>29.11.2.2 Member functions [strstreambuf.members]</ins></h4>
<ol>
<pre><ins>void freeze(bool freezefl = true);</ins></pre>
<li><ins>
<i>Effects:</i> If <code>strmode &amp; dynamic</code> is nonzero, alters the
freeze status of the dynamic array object as follows:
  <ol>
  <li><ins>
&mdash; If <code>freezefl</code> is <code>true</code>, the function sets
<code>frozen</code> in <code>strmode</code>.
  </ins></li>
  <li><ins>
&mdash; Otherwise, it clears <code>frozen</code> in <code>strmode</code>.
  </ins></li>
  </ol>
</ins></li>

<pre><ins>char* str();</ins></pre>
<li><ins>
<i>Effects:</i> Calls <code>freeze()</code>, then returns the beginning pointer
for the input sequence, <code>gbeg</code>.
</ins></li>
<li><ins>
<i>Remarks:</i> The return value can be a null pointer.
</ins></li>

<pre><ins>int pcount() const;</ins></pre>
<li><ins>
<i>Effects:</i> If the next pointer for the output sequence,
<code>pnext</code>, is a null pointer, returns zero. Otherwise, returns the
current effective length of the array object as the next pointer minus the
beginning pointer for the output sequence, <code>pnext - pbeg</code>.
</ins></li>
</ol>

<h4><ins>29.11.2.3 <code>strstreambuf</code> overridden virtual functions [strstreambuf.virtuals]</ins></h4>
<ol>
<pre><ins>int_type overflow(int_type c = EOF) override;</ins></pre>
<li><ins>
<i>Effects:</i> Appends the character designated by <code>c</code> to the
output sequence, if possible, in one of two ways:
  <ol>
  <li><ins>
&mdash; If <code>c != EOF</code> and if either the output sequence has a write position available or the function makes
a write position available (as described below), assigns <code>c</code> to <code>*pnext++</code>.
Returns <code>(unsigned char)c</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>c == EOF</code>, there is no character to append.
Returns a value other than <code>EOF</code>.
  </ins></li>
  </ol>
</ins></li>
<li><ins>
Returns <code>EOF</code> to indicate failure.
</ins></li>
<li><ins>
<i>Remarks:</i> The function can alter the number of write positions available
as a result of any call.
</ins></li>
<li><ins>
To make a write position available, the function reallocates (or initially
allocates) an array object with a sufficient number of elements <code>n</code>
to hold the current array object (if any), plus at least one additional write
position. How many additional write positions are made available is otherwise
unspecified.<sup>328</sup> If <code>palloc</code> is not a null pointer, the
function calls <code>(*palloc)(n)</code> to allocate the new dynamic array
object. Otherwise, it evaluates the expression <code>new charT[n]</code>. In
either case, if the allocation fails, the function returns <code>EOF</code>.
Otherwise, it sets <code>allocated</code> in <code>strmode</code>.
</ins></li>
<li><ins>
To free a previously existing dynamic array object whose first element address
is <code>p</code>: If <code>pfree</code> is not a null pointer, the function
calls <code>(*pfree)(p)</code>. Otherwise, it evaluates the expression
<code>delete[]p</code>.
</ins></li>
<li><ins>
If <code>(strmode &amp; dynamic) == 0</code>, or if <code>(strmode &amp;
frozen) != 0</code>, the function cannot extend the array (reallocate it with
greater length) to make a write position available.
</ins></li>

<pre><ins>int_type pbackfail(int_type c = EOF) override;</ins></pre>
<li><ins>
Puts back the character designated by <code>c</code> to the input sequence, if
possible, in one of three ways:
  <ol>
  <li><ins>
&mdash; If <code>c != EOF</code>, if the input sequence has a putback position
available, and if <code>(char)c == gnext[-1]</code>, assigns
<code>gnext - 1 to gnext</code>.
Returns <code>c</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>c != EOF</code>, if the input sequence has a putback position
available, and if <code>strmode &amp; constant</code> is zero, assigns
<code>c</code> to <code>*--gnext</code>.
Returns <code>c</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>c == EOF</code> and if the input sequence has a putback
position available, assigns <code>gnext - 1</code> to <code>gnext</code>.
  </ins></li>
  </ol>
</ins></li>
<li><ins>
Returns a value other than <code>EOF</code>. Returns <code>EOF</code> to
indicate failure.
</ins></li>
<li><ins>
<i>Remarks:</i> If the function can succeed in more than one of these ways, it
is unspecified which way is chosen. The function can alter the number of
putback positions available as a result of any call.
</ins></li>


<pre><ins>int_type underflow() override;</ins></pre>
<li><ins>
<i>Effects:</i> Reads a character from the input sequence, if possible, without
moving the stream position past it, as follows:
  <ol>
  <li><ins>
&mdash; If the input sequence has a read position available, the function
signals success by returning <code>(unsigned char)*gnext</code>.
  </ins></li>
  <li><ins>
&mdash; Otherwise, if the current write next pointer <code>pnext</code> is not
a null pointer and is greater than the current read end pointer
<code>gend</code>, makes a read position available by assigning to
<code>gend</code> a value greater than <code>gnext</code> and no greater than
<code>pnext</code>.

Returns <code>(unsigned char)*gnext</code>.
  </ins></li>
  </ol>
</ins></li>
<li><ins>
Returns <code>EOF</code> to indicate failure.
</ins></li>
<li><ins>
<i>Remarks:</i> The function can alter the number of read positions available
as a result of any call.
</ins></li>

<pre><ins>pos_type seekoff(off_type off, seekdir way, openmode which = in | out) override;</ins></pre>
<li><ins>
<i>Effects:</i> Alters the stream position within one of the controlled
sequences, if possible, as indicated in Table 151.
</ins></li>

<table align="center">
<caption><ins>
Table 151: seekoff positioning [tab:depr.strstreambuf.seekoff.pos]
</ins></caption>
<tr>
  <th><ins>Conditions</ins></th>
  <th><ins>Result</ins></th>
</tr>
<tr>
  <td><ins><code>(which &amp; ios::in) != 0</code></ins></td>
  <td><ins>positions the input sequence</ins></td>
</tr>
<tr>
  <td><ins><code>(which &amp; ios::out) != 0</code></ins></td>
  <td><ins>positions the output sequence
</ins></td>
</tr>
<tr>
  <td><ins>
    <code>(which &amp; (ios::in | ios::out)) ==  (ios::in | ios::out)</code>
    and either <code>way == ios::beg</code> or <code>way == ios::end</code>
  </ins></td>
  <td><ins>positions both the input and the output sequences</ins></td>
</tr>
<tr>
  <td><ins>Otherwise</ins></td>
  <td><ins>the positioning operation fails.</ins></td>
</tr>
</table>

<li><ins>
For a sequence to be positioned, if its next pointer is a null pointer, the
positioning operation fails. Otherwise, the function determines
<code>newoff</code> as indicated in Table 152.
</ins></li>

<table align="center">
<caption><ins>
Table 152: newoff values [tab:depr.strstreambuf.seekoff.newoff]
</ins></caption>
<tr>
  <th><ins>Condition</ins></th>
  <th><ins><code>newoff</code> Value</ins></th>
</tr>
<tr>
  <td><ins><code>way == ios::beg</code></ins></td>
  <td><ins>0</ins></td>
</tr>
<tr>
  <td><ins><code>way == ios::cur</code></ins></td>
  <td><ins>the next pointer minus the beginning pointer (<code>xnext - xbeg</code>).</ins></td>
</tr>
<tr>
  <td><ins><code>way == ios::end</code></ins></td>
  <td><ins><code>seekhigh</code> minus the beginning pointer (<code>seekhigh - xbeg</code>).</ins></td>
</tr>
</table>

<li><ins>
If <code>(newoff + off) &lt; (seeklow - xbeg)</code> or
<code>(seekhigh - xbeg) &lt; (newoff + off)</code>, the positioning operation
fails. Otherwise, the function assigns <code>xbeg + newoff + off</code> to the
next pointer <code>xnext</code>.
</ins></li>
<li><ins>
<i>Returns:</i> <code>pos_type(newoff)</code>, constructed from the resultant
offset <code>newoff</code> (of type <code>off_type)</code>, that stores the
resultant stream position, if possible. If the positioning operation fails, or
if the constructed object cannot represent the resultant stream position, the
return value is <code>pos_type(off_type(-1))</code>.
</ins></li>

<pre><ins>pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override;</ins></pre>
<li><ins>
<i>Effects:</i> Alters the stream position within one of the controlled
sequences, if possible, to correspond to the stream position stored in
<code>sp</code> (as described below).
  <ol>
  <li><ins>
&mdash; If <code>(which &amp; ios::in) != 0</code>, positions the input sequence.
  </ins></li>
  <li><ins>
&mdash; If <code>(which &amp; ios::out) != 0</code>, positions the output sequence.
  </ins></li>
  <li><ins>
&mdash; If the function positions neither sequence, the positioning operation fails.
  </ins></li>
  </ol>
</ins></li>
<li><ins>
For a sequence to be positioned, if its next pointer is a null pointer, the
positioning operation fails. Otherwise, the function determines
<code>newoff</code> from <code>sp.offset()</code>:
  <ol>
  <li><ins>
&mdash; If <code>newoff</code> is an invalid stream position, has a negative
value, or has a value greater than <code>(seekhigh - seeklow)</code>, the
positioning operation fails
  </ins></li>
  <li><ins>
&mdash; Otherwise, the function adds <code>newoff</code> to the beginning
pointer <code>xbeg</code> and stores the result in the next pointer
<code>xnext</code>.
  </ins></li>
  </ol>
</ins></li>
<li><ins>
<i>Returns:</i> <code>pos_type(newoff)</code>, constructed from the resultant
offset <code>newoff</code> (of type <code>off_type</code>), that stores the
resultant stream position, if possible. If the positioning operation fails, or
if the constructed object cannot represent the resultant stream position, the
return value is <code>pos_type(off_type(-1))</code>.
</ins></li>

<pre><ins>streambuf&lt;char&gt;* setbuf(char* s, streamsize n) override;</ins></pre>
<li><ins>
<i>Effects:</i> Behavior is implementation-defined, except that
<code>setbuf(0, 0)</code> has no effect.
</ins></li>
</ol>

<h4><ins>29.11.3 Class <code>istrstream</code> [istrstream]</ins></h4>
<pre><ins>
namespace std {
  class istrstream : public basic_istream&lt;char&gt; {
  public:
    explicit istrstream(const char* s);
    explicit istrstream(char* s);
    istrstream(const char* s, streamsize n);
    istrstream(char* s, streamsize n);
    virtual ~istrstream();

    strstreambuf* rdbuf() const;
    char* str();
  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</ins></pre>

<ol>
<li><ins>
The class <code>istrstream</code> supports the reading of objects of class
<code>strstreambuf</code>. It supplies a <code>strstreambuf</code> object to
control the associated array object. For the sake of exposition, the maintained
data is presented here as:
  <ol>
  <li><ins>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </ins></li>
  </ol>
</ins></li>
</ol>

<h4><ins>29.11.3.1 <code>istrstream</code> constructors [istrstream.cons]</ins></h4>
<ol>
<pre><ins>explicit istrstream(const char* s);
explicit istrstream(char* s);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>istream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf(s, 0)</code>. <code>s</code> shall
designate the first element of an NTBS.
</ins></li>

<pre><ins>istrstream(const char* s, streamsize n);
istrstream(char* s, streamsize n);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>istream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf(s, n)</code>. <code>s</code> shall
designate the first element of an array whose length is <code>n</code>
elements, and <code>n</code> shall be greater than zero.
</ins></li>
</ol>

<h4><ins>29.11.3.2 Member functions [istrstream.members]</ins></h4>
<ol>
<pre><ins>strstreambuf* rdbuf() const;</ins></pre>
<li><ins>
<i>Returns:</i> <code>const_cast&lt;strstreambuf*&gt;(&amp;sb)</code>.
</ins></li>

<pre><ins>char* str();</ins></pre>
<li><ins>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</ins></li>
</ol>

<h4><ins>12.4 Class <code>ostrstream</code> [ostrstream]</ins></h4>
<pre><ins>
namespace std {
  class ostrstream : public basic_ostream&lt;char&gt; {
  public:
    ostrstream();
    ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);
    virtual ~ostrstream();
    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    char* str();
    int pcount() const;
  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</ins></pre>
<ol>
<li><ins>
The class <code>ostrstream</code> supports the writing of objects of class
<code>strstreambuf</code>.  It supplies a <code>strstreambuf</code> object to
control the associated array object. For the sake of exposition, the maintained
data is presented here as:
  <ol>
  <li><ins>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </ins></li>
  </ol>
</ins></li>
</ol>

<h4><ins>29.11.4.1 <code>ostrstream</code> constructors [ostrstream.cons]</ins></h4>
<ol>
<pre><ins>ostrstream();</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>ostream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf()</code>.
</ins></li>

<pre><ins>ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>ostream(&amp;sb)</code>,
and <code>sb</code> with one of two constructors:
  <ol>
  <li><ins>
&mdash; If <code>(mode &amp; app) == 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements.
The constructor is <code>strstreambuf(s, n, s)</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>(mode &amp; app) != 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements that
contains an NTBS whose first element is designated by <code>s</code>. The
constructor is <code>strstreambuf(s, n, s + std::strlen(s))</code>.<sup>329</sup>
  </ins></li>
  </ol>
</ins></li>
</ol>

<h4><ins>29.11.4.2 Member functions [ostrstream.members]</ins></h4>
<ol>
<pre><ins>strstreambuf* rdbuf() const;</ins></pre>
<li><ins>
<i>Returns:</i> <code>(strstreambuf*)&amp;sb</code>.
</ins></li>

<pre><ins>void freeze(bool freezefl = true);</ins></pre>
<li><ins>
<i>Effects:</i> Calls <code>rdbuf()-&gt;freeze(freezefl)</code>.
</ins></li>

<pre><ins>char* str();</ins></pre>
<li><ins>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</ins></li>

<pre><ins>int pcount() const;</ins></pre>
<li><ins>
<i>Returns:</i> <code>rdbuf()-&gt;pcount()</code>.
</ins></li>
</ol>

<h4><ins>29.11.5 Class <code>strstream</code> [strstream]</ins></h4>
<pre><ins>
namespace std {
  class strstream
    : public basic_iostream&lt;char&gt; {
  public:
    // types
    using char_type = char;
    using int_type  = char_traits&lt;char&gt;::int_type;
    using pos_type  = char_traits&lt;char&gt;::pos_type;
    using off_type  = char_traits&lt;char&gt;::off_type;

    // constructors/destructor
    strstream();
    strstream(char* s, int n,
              ios_base::openmode mode = ios_base::in|ios_base::out);
    virtual ~strstream();

    // members
    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    int pcount() const;
    char* str();

  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</ins></pre>
<ol>
<li><ins>
The class <code>strstream</code> supports reading and writing from objects of
class <code>strstreambuf</code>. It supplies a <code>strstreambuf</code> object
to control the associated array object. For the sake of exposition, the
maintained data is presented here as:
  <ol>
  <li><ins>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </ins></li>
  </ol>
</ins></li>
</ol>

<h4><ins>29.11.5.1 <code>strstream</code> constructors [strstream.cons]</ins></h4>
<ol>
<pre><ins>strstream();</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>iostream(&amp;sb)</code>.
</ins></li>

<pre><ins>strstream(char* s, int n,
          ios_base::openmode mode = ios_base::in|ios_base::out);</ins></pre>
<li><ins>
<i>Effects:</i> Initializes the base class with <code>iostream(&amp;sb)</code>,
and <code>sb</code> with one of the two constructors:
  <ol>
  <li><ins>
&mdash; If <code>(mode &amp; app) == 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements. The
constructor is <code>strstreambuf(s,n,s)</code>.
  </ins></li>
  <li><ins>
&mdash; If <code>(mode &amp; app) != 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements that
contains an NTBS whose first element is designated by <code>s</code>. The
constructor is <code>strstreambuf(s,n,s + std::strlen(s))</code>.
  </ins></li>
  </ol>
</ins></li>
</ol>

<h4><ins>29.11.5.2 <code>strstream</code> destructor [strstream.dest]</ins></h4>
<ol>
<pre><ins>virtual ~strstream();</ins></pre>
<li><ins>
<i>Effects:</i> Destroys an object of class <code>strstream</code>.
</ins></li>
</ol>

<h4><ins>29.11.5.3 <code>strstream</code> operations [strstream.oper]</ins></h4>
<ol>
<pre><ins>strstreambuf* rdbuf() const;</ins></pre>
<li><ins>
<i>Returns:</i> <code>const_cast&lt;strstreambuf*&gt;(&amp;sb)</code>.
</ins></li>

<pre><ins>void freeze(bool freezefl = true);</ins></pre>
<li><ins>
<i>Effects:</i> Calls <code>rdbuf()-&gt;freeze(freezefl)</code>.
</ins></li>

<pre><ins>char* str();</ins></pre>
<li><ins>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</ins></li>

<pre><ins>int pcount() const;</ins></pre>
<li><ins>
<i>Returns:</i> <code>rdbuf()-&gt;pcount()</code>.
</ins></li>
</ol>


<h4><del>D.12 <code>char*</code> streams [depr.str.strstreams]</del></h4>
<h4><del>D.12.1 Header <code>&lt;strstream&gt;</code> synopsis [depr.strstream.syn]</del></h4>
<ol>
<li><del>
The header <code>&lt;strstream&gt;</code> defines types that associate stream
buffers with character array objects and assist reading and writing such
objects.
</del></li>
</ol>
<blockquote><pre><del>
namespace std {
  class strstreambuf;
  class istrstream;
  class ostrstream;
  class strstream;
}
</del></pre></blockquote>

<h4><del>D.12.2 Class <code>strstreambuf</code> [depr.strstreambuf]</del></h4>
<blockquote><pre><del>
namespace std {
  class strstreambuf : public basic_streambuf&lt;char&gt; {
  public:
    strstreambuf() : strstreambuf(0) {}
    explicit strstreambuf(streamsize alsize_arg);
    strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));
    strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr);
    strstreambuf(const char* gnext_arg, streamsize n);

    strstreambuf(signed char* gnext_arg, streamsize n,
                 signed char* pbeg_arg = nullptr);
    strstreambuf(const signed char* gnext_arg, streamsize n);
    strstreambuf(unsigned char* gnext_arg, streamsize n,
                 unsigned char* pbeg_arg = nullptr);
    strstreambuf(const unsigned char* gnext_arg, streamsize n);

    virtual ~strstreambuf();

    void  freeze(bool freezefl = true);
    char* str();
    int   pcount();

  protected:
    int_type overflow (int_type c = EOF) override;
    int_type pbackfail(int_type c = EOF) override;
    int_type underflow() override;
    pos_type seekoff(off_type off, ios_base::seekdir way,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    pos_type seekpos(pos_type sp,
                     ios_base::openmode which = ios_base::in | ios_base::out) override;
    streambuf* setbuf(char* s, streamsize n) override;

  private:
    using strstate = T1;               <i>// exposition only</i>
    static const strstate allocated;   <i>// exposition only</i>
    static const strstate constant;    <i>// exposition only</i>
    static const strstate dynamic;     <i>// exposition only</i>
    static const strstate frozen;      <i>// exposition only</i>
    strstate strmode;                  <i>// exposition only</i>
    streamsize alsize;                 <i>// exposition only</i>
    void* (*palloc)(size_t);           <i>// exposition only</i>
    void (*pfree)(void*);              <i>// exposition only</i>
  };
}
</del></pre></blockquote>

<ol>
<li><del>
The class <code>strstreambuf</code> associates the input sequence, and possibly
the output sequence, with an object of some character array type, whose
elements store arbitrary values. The array object has several attributes.
</del></li>
<li><del>
[<i>Note:</i> For the sake of exposition, these are represented as elements of
a bitmask type (indicated here as <code>T1</code>) called
<code>strstate</code>. The elements are:
  <ol>
  <li><del>
&mdash; <code>allocated</code>, set when a dynamic array object has been
allocated, and hence should be freed by the destructor for the
<code>strstreambuf</code> object;
  </del></li>
  <li><del>
&mdash; <code>constant</code>, set when the array object has
<code>const</code> elements, so the output sequence cannot be written;
  </del></li>
  <li><del>
&mdash; <code>dynamic</code>, set when the array object is allocated (or
reallocated) as necessary to hold a character sequence that can change in
length;
  </del></li>
  <li><del>
&mdash; <code>frozen</code>, set when the program has requested that the array
object not be altered, reallocated, or freed.
  </del></li>
  </ol>
<i>&mdash;end note</i>]
</del></li>
<li><del>
[<i>Note:</i> For the sake of exposition, the maintained data is presented here
as:
  <ol>
  <li><del>
&mdash; <code>strstate strmode</code>, the attributes of the array object
associated with the <code>strstreambuf</code> object;
  </del></li>
  <li><del>
&mdash; <code>int alsize</code>, the suggested minimum size for a dynamic array
object;
  </del></li>
  <li><del>
&mdash; <code>void* (*palloc)(size_t)</code>, points to the function to call to
allocate a dynamic array object;
  </del></li>
  <li><del>
&mdash; <code>void (*pfree)(void*)</code>, points to the function to call to
free a dynamic array object.
  </del></li>
  </ol>
<i>&mdash;end note</i>]
</del></li>
<li><del>
Each object of class <code>strstreambuf</code> has a seekable area, delimited
by the pointers <code>seeklow</code> and <code>seekhigh</code>. If
<code>gnext</code> is a null pointer, the seekable area is undefined.
Otherwise, <code>seeklow</code> equals <code>gbeg</code> and
<code>seekhigh</code> is either <code>pend</code>, if <code>pend</code> is not
a null pointer, or <code>gend</code>.
</del></li>
</ol>

<h4><del>D.12.2.1 <code>strstreambuf</code> constructors [depr.strstreambuf.cons]</del></h4>
<ol>
<pre><del>explicit strstreambuf(streamsize alsize_arg);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 148.
</del></li>
</ol>

<table align="center">
<caption><del>
Table 148: <code>strstreambuf(streamsize)</code> effects
[tab:depr.strstreambuf.cons.sz]
</del></caption>
<tr>
  <th><del>Element</del></th>
  <th><del>Value</del></th>
</tr>
<tr>
  <td><del><code>strmode</code></del></td>
  <td><del><code>dynamic</code></del></td>
</tr>
<tr>
  <td><del><code>alsize</code></del></td>
  <td><del><code>alsize_arg</code></del></td>
</tr>
<tr>
  <td><del><code>palloc</code></del></td>
  <td><del>a null pointer</del></td>
</tr>
<tr>
  <td><del><code>pfree</code></del></td>
  <td><del>a null pointer</del></td>
</tr>
</table>

<ol start="2">
<pre><del>strstreambuf(void* (*palloc_arg)(size_t), void (*pfree_arg)(void*));</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 149.
</del></li>
</ol>
<table align="center">
<caption><del>
Table 149: <code>strstreambuf(void* (*)(size_t), void (*)(void*))</code> effects
[tab:depr.strstreambuf.cons.alloc]
</del></caption>
<tr>
  <th><del>Element</del></th>
  <th><del>Value</del></th>
</tr>
<tr>
  <td><del><code>strmode</code></del></td>
  <td><del><code>dynamic</code></del></td>
</tr>
<tr>
  <td><del><code>alsize</code></del></td>
  <td><del>an unspecified value</del></td>
</tr>
<tr>
  <td><del><code>palloc</code></del></td>
  <td><del><code>palloc_arg</code></del></td>
</tr>
<tr>
  <td><del><code>pfree</code></del></td>
  <td><del><code>pfree_arg</code></del></td>
</tr>
</table>

<ol start="3">
<pre><del>strstreambuf(char* gnext_arg, streamsize n, char* pbeg_arg = nullptr);
strstreambuf(signed char* gnext_arg, streamsize n,
             signed char* pbeg_arg = nullptr);
strstreambuf(unsigned char* gnext_arg, streamsize n,
             unsigned char* pbeg_arg = nullptr);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>streambuf()</code>. The
postconditions of this function are indicated in Table 150.
</del></li>
</ol>

<table align="center">
<caption><del>
Table 150: <code>strstreambuf(charT*, streamsize, charT*)</code> effects
[tab:depr.strstreambuf.cons.ptr]
</del></caption>
<tr>
  <th><del>Element</del></th>
  <th><del>Value</del></th>
</tr>
<tr>
  <td><del><code>strmode</code></del></td>
  <td><del>0</del></td>
</tr>
<tr>
  <td><del><code>alsize</code></del></td>
  <td><del>an unspecified value</del></td>
</tr>
<tr>
  <td><del><code>palloc</code></del></td>
  <td><del>a null pointer</del></td>
</tr>
<tr>
  <td><del><code>pfree</code></del></td>
  <td><del>a null pointer</del></td>
</tr>
</table>

<ol start="4">
<li><del>
<code>gnext_arg</code> shall point to the first element of an array object
whose number of elements <code>N</code> is determined as follows:
  <ol>
  <li><del>
&mdash; If <code>n &gt; 0</code>, <code>N</code> is <code>n</code>.
  </del></li>
  <li><del>
&mdash; If <code>n == 0</code>, <code>N</code> is <code>std::strlen(gnext_arg)</code>.
  </del></li>
  <li><del>
&mdash; If <code>n &lt; 0</code>, <code>N</code> is <code>INT_MAX</code>.<sup>327</sup>
  </del></li>
  </ol>
</del></li>

<li><del>
If <code>pbeg_arg</code> is a null pointer, the function executes:
<blockquote><pre><del>setg(gnext_arg, gnext_arg, gnext_arg + N);</del></pre></blockquote>
</del></li>
<li><del>
Otherwise, the function executes:
<blockquote><pre><del>setg(gnext_arg, gnext_arg, pbeg_arg);
setp(pbeg_arg,  pbeg_arg + N);</del></pre></blockquote>
</del></li>

<pre><del>strstreambuf(const char* gnext_arg, streamsize n);
strstreambuf(const signed char* gnext_arg, streamsize n);
strstreambuf(const unsigned char* gnext_arg, streamsize n);</del></pre>
<li><del>
<i>Effects:</i> Behaves the same as
<code>strstreambuf((char*)gnext_arg,n)</code>, except that the constructor also
sets <code>constant</code> in <code>strmode</code>.
</del></li>

<pre><del>virtual ~strstreambuf();</del></pre>
<li><del>
<i>Effects:</i> Destroys an object of class <code>strstreambuf</code>. The
function frees the dynamically allocated array object only if <code>(strmode
&amp; allocated) != 0</code> and <code>(strmode &amp; frozen) == 0</code>.
(D.12.2.3 describes how a dynamically allocated array object is freed.)
</del></li>
</ol>

<h4><del>D.12.2.2 Member functions [depr.strstreambuf.members]</del></h4>
<ol>
<pre><del>void freeze(bool freezefl = true);</del></pre>
<li><del>
<i>Effects:</i> If <code>strmode &amp; dynamic</code> is nonzero, alters the
freeze status of the dynamic array object as follows:
  <ol>
  <li><del>
&mdash; If <code>freezefl</code> is <code>true</code>, the function sets
<code>frozen</code> in <code>strmode</code>.
  </del></li>
  <li><del>
&mdash; Otherwise, it clears <code>frozen</code> in <code>strmode</code>.
  </del></li>
  </ol>
</del></li>

<pre><del>char* str();</del></pre>
<li><del>
<i>Effects:</i> Calls <code>freeze()</code>, then returns the beginning pointer
for the input sequence, <code>gbeg</code>.
</del></li>
<li><del>
<i>Remarks:</i> The return value can be a null pointer.
</del></li>

<pre><del>int pcount() const;</del></pre>
<li><del>
<i>Effects:</i> If the next pointer for the output sequence,
<code>pnext</code>, is a null pointer, returns zero. Otherwise, returns the
current effective length of the array object as the next pointer minus the
beginning pointer for the output sequence, <code>pnext - pbeg</code>.
</del></li>
</ol>

<h4><del>D.12.2.3 <code>strstreambuf</code> overridden virtual functions [depr.strstreambuf.virtuals]</del></h4>
<ol>
<pre><del>int_type overflow(int_type c = EOF) override;</del></pre>
<li><del>
<i>Effects:</i> Appends the character designated by <code>c</code> to the
output sequence, if possible, in one of two ways:
  <ol>
  <li><del>
&mdash; If <code>c != EOF</code> and if either the output sequence has a write position available or the function makes
a write position available (as described below), assigns <code>c</code> to <code>*pnext++</code>.
Returns <code>(unsigned char)c</code>.
  </del></li>
  <li><del>
&mdash; If <code>c == EOF</code>, there is no character to append.
Returns a value other than <code>EOF</code>.
  </del></li>
  </ol>
</del></li>
<li><del>
Returns <code>EOF</code> to indicate failure.
</del></li>
<li><del>
<i>Remarks:</i> The function can alter the number of write positions available
as a result of any call.
</del></li>
<li><del>
To make a write position available, the function reallocates (or initially
allocates) an array object with a sufficient number of elements <code>n</code>
to hold the current array object (if any), plus at least one additional write
position. How many additional write positions are made available is otherwise
unspecified.<sup>328</sup> If <code>palloc</code> is not a null pointer, the
function calls <code>(*palloc)(n)</code> to allocate the new dynamic array
object. Otherwise, it evaluates the expression <code>new charT[n]</code>. In
either case, if the allocation fails, the function returns <code>EOF</code>.
Otherwise, it sets <code>allocated</code> in <code>strmode</code>.
</del></li>
<li><del>
To free a previously existing dynamic array object whose first element address
is <code>p</code>: If <code>pfree</code> is not a null pointer, the function
calls <code>(*pfree)(p)</code>. Otherwise, it evaluates the expression
<code>delete[]p</code>.
</del></li>
<li><del>
If <code>(strmode &amp; dynamic) == 0</code>, or if <code>(strmode &amp;
frozen) != 0</code>, the function cannot extend the array (reallocate it with
greater length) to make a write position available.
</del></li>

<pre><del>int_type pbackfail(int_type c = EOF) override;</del></pre>
<li><del>
Puts back the character designated by <code>c</code> to the input sequence, if
possible, in one of three ways:
  <ol>
  <li><del>
&mdash; If <code>c != EOF</code>, if the input sequence has a putback position
available, and if <code>(char)c == gnext[-1]</code>, assigns
<code>gnext - 1 to gnext</code>.
Returns <code>c</code>.
  </del></li>
  <li><del>
&mdash; If <code>c != EOF</code>, if the input sequence has a putback position
available, and if <code>strmode &amp; constant</code> is zero, assigns
<code>c</code> to <code>*--gnext</code>.
Returns <code>c</code>.
  </del></li>
  <li><del>
&mdash; If <code>c == EOF</code> and if the input sequence has a putback
position available, assigns <code>gnext - 1</code> to <code>gnext</code>.
  </del></li>
  </ol>
</del></li>
<li><del>
Returns a value other than <code>EOF</code>. Returns <code>EOF</code> to
indicate failure.
</del></li>
<li><del>
<i>Remarks:</i> If the function can succeed in more than one of these ways, it
is unspecified which way is chosen. The function can alter the number of
putback positions available as a result of any call.
</del></li>


<pre><del>int_type underflow() override;</del></pre>
<li><del>
<i>Effects:</i> Reads a character from the input sequence, if possible, without
moving the stream position past it, as follows:
  <ol>
  <li><del>
&mdash; If the input sequence has a read position available, the function
signals success by returning <code>(unsigned char)*gnext</code>.
  </del></li>
  <li><del>
&mdash; Otherwise, if the current write next pointer <code>pnext</code> is not
a null pointer and is greater than the current read end pointer
<code>gend</code>, makes a read position available by assigning to
<code>gend</code> a value greater than <code>gnext</code> and no greater than
<code>pnext</code>.

Returns <code>(unsigned char)*gnext</code>.
  </del></li>
  </ol>
</del></li>
<li><del>
Returns <code>EOF</code> to indicate failure.
</del></li>
<li><del>
<i>Remarks:</i> The function can alter the number of read positions available
as a result of any call.
</del></li>

<pre><del>pos_type seekoff(off_type off, seekdir way, openmode which = in | out) override;</del></pre>
<li><del>
<i>Effects:</i> Alters the stream position within one of the controlled
sequences, if possible, as indicated in Table 151.
</del></li>
<li><del>
For a sequence to be positioned, if its next pointer is a null pointer, the
positioning operation fails. Otherwise, the function determines
<code>newoff</code> as indicated in Table 152.
</del></li>
<li><del>
If <code>(newoff + off) &lt; (seeklow - xbeg)</code> or
<code>(seekhigh - xbeg) &lt; (newoff + off)</code>, the positioning operation
fails. Otherwise, the function assigns <code>xbeg + newoff + off</code> to the
next pointer <code>xnext</code>.
</del></li>
<li><del>
<i>Returns:</i> <code>pos_type(newoff)</code>, constructed from the resultant
offset <code>newoff</code> (of type <code>off_type)</code>, that stores the
resultant stream position, if possible. If the positioning operation fails, or
if the constructed object cannot represent the resultant stream position, the
return value is <code>pos_type(off_type(-1))</code>.
</del></li>


<table align="center">
<caption><del>
Table 151: seekoff positioning [tab:depr.strstreambuf.seekoff.pos]
</del></caption>
<tr>
  <th><del>Conditions</del></th>
  <th><del>Result</del></th>
</tr>
<tr>
  <td><del><code>(which &amp; ios::in) != 0</code></del></td>
  <td><del>positions the input sequence</del></td>
</tr>
<tr>
  <td><del><code>(which &amp; ios::out) != 0</code></del></td>
  <td><del>positions the output sequence
</del></td>
</tr>
<tr>
  <td><del>
    <code>(which &amp; (ios::in | ios::out)) ==  (ios::in | ios::out)</code>
    and either <code>way == ios::beg</code> or <code>way == ios::end</code>
  </del></td>
  <td><del>positions both the input and the output sequences</del></td>
</tr>
<tr>
  <td><del>Otherwise</del></td>
  <td><del>the positioning operation fails.</del></td>
</tr>
</table>

<table align="center">
<caption><del>
Table 152: newoff values [tab:depr.strstreambuf.seekoff.newoff]
</del></caption>
<tr>
  <th><del>Condition</del></th>
  <th><del><code>newoff</code> Value</del></th>
</tr>
<tr>
  <td><del><code>way == ios::beg</code></del></td>
  <td><del>0</del></td>
</tr>
<tr>
  <td><del><code>way == ios::cur</code></del></td>
  <td><del>the next pointer minus the beginning pointer (<code>xnext - xbeg</code>).</del></td>
</tr>
<tr>
  <td><del><code>way == ios::end</code></del></td>
  <td><del><code>seekhigh</code> minus the beginning pointer (<code>seekhigh - xbeg</code>).</del></td>
</tr>
</table>


<pre><del>pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override;</del></pre>
<li><del>
<i>Effects:</i> Alters the stream position within one of the controlled
sequences, if possible, to correspond to the stream position stored in
<code>sp</code> (as described below).
  <ol>
  <li><del>
&mdash; If <code>(which &amp; ios::in) != 0</code>, positions the input sequence.
  </del></li>
  <li><del>
&mdash; If <code>(which &amp; ios::out) != 0</code>, positions the output sequence.
  </del></li>
  <li><del>
&mdash; If the function positions neither sequence, the positioning operation fails.
  </del></li>
  </ol>
</del></li>
<li><del>
For a sequence to be positioned, if its next pointer is a null pointer, the
positioning operation fails. Otherwise, the function determines
<code>newoff</code> from <code>sp.offset()</code>:
  <ol>
  <li><del>
&mdash; If <code>newoff</code> is an invalid stream position, has a negative
value, or has a value greater than <code>(seekhigh - seeklow)</code>, the
positioning operation fails
  </del></li>
  <li><del>
&mdash; Otherwise, the function adds <code>newoff</code> to the beginning
pointer <code>xbeg</code> and stores the result in the next pointer
<code>xnext</code>.
  </del></li>
  </ol>
</del></li>
<li><del>
<i>Returns:</i> <code>pos_type(newoff)</code>, constructed from the resultant
offset <code>newoff</code> (of type <code>off_type</code>), that stores the
resultant stream position, if possible. If the positioning operation fails, or
if the constructed object cannot represent the resultant stream position, the
return value is <code>pos_type(off_type(-1))</code>.
</del></li>

<pre><del>streambuf&lt;char&gt;* setbuf(char* s, streamsize n) override;</del></pre>
<li><del>
<i>Effects:</i> Behavior is implementation-defined, except that
<code>setbuf(0, 0)</code> has no effect.
</del></li>
</ol>

<h4><del>D.12.3 Class <code>istrstream</code> [depr.istrstream]</del></h4>
<pre><del>
namespace std {
  class istrstream : public basic_istream&lt;char&gt; {
  public:
    explicit istrstream(const char* s);
    explicit istrstream(char* s);
    istrstream(const char* s, streamsize n);
    istrstream(char* s, streamsize n);
    virtual ~istrstream();

    strstreambuf* rdbuf() const;
    char* str();
  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</del></pre>

<ol>
<li><del>
The class <code>istrstream</code> supports the reading of objects of class
<code>strstreambuf</code>. It supplies a <code>strstreambuf</code> object to
control the associated array object. For the sake of exposition, the maintained
data is presented here as:
  <ol>
  <li><del>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </del></li>
  </ol>
</del></li>
</ol>

<h4><del>D.12.3.1 <code>istrstream</code> constructors [depr.istrstream.cons]</del></h4>
<ol>
<pre><del>explicit istrstream(const char* s);
explicit istrstream(char* s);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>istream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf(s, 0)</code>. <code>s</code> shall
designate the first element of an NTBS.
</del></li>

<pre><del>istrstream(const char* s, streamsize n);
istrstream(char* s, streamsize n);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>istream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf(s, n)</code>. <code>s</code> shall
designate the first element of an array whose length is <code>n</code>
elements, and <code>n</code> shall be greater than zero.
</del></li>
</ol>

<h4><del>D.12.3.2 Member functions [depr.istrstream.members]</del></h4>
<ol>
<pre><del>strstreambuf* rdbuf() const;</del></pre>
<li><del>
<i>Returns:</i> <code>const_cast&lt;strstreambuf*&gt;(&amp;sb)</code>.
</del></li>

<pre><del>char* str();</del></pre>
<li><del>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</del></li>
</ol>

<h4><del>12.4 Class <code>ostrstream</code> [depr.ostrstream]</del></h4>
<pre><del>
namespace std {
  class ostrstream : public basic_ostream&lt;char&gt; {
  public:
    ostrstream();
    ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);
    virtual ~ostrstream();
    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    char* str();
    int pcount() const;
  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</del></pre>
<ol>
<li><del>
The class <code>ostrstream</code> supports the writing of objects of class
<code>strstreambuf</code>.  It supplies a <code>strstreambuf</code> object to
control the associated array object. For the sake of exposition, the maintained
data is presented here as:
  <ol>
  <li><del>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </del></li>
  </ol>
</del></li>
</ol>

<h4><del>D.12.4.1 <code>ostrstream</code> constructors [depr.ostrstream.cons]</del></h4>
<ol>
<pre><del>ostrstream();</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>ostream(&amp;sb)</code>
and <code>sb</code> with <code>strstreambuf()</code>.
</del></li>

<pre><del>ostrstream(char* s, int n, ios_base::openmode mode = ios_base::out);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>ostream(&amp;sb)</code>,
and <code>sb</code> with one of two constructors:
  <ol>
  <li><del>
&mdash; If <code>(mode &amp; app) == 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements.
The constructor is <code>strstreambuf(s, n, s)</code>.
  </del></li>
  <li><del>
&mdash; If <code>(mode &amp; app) != 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements that
contains an NTBS whose first element is designated by <code>s</code>. The
constructor is <code>strstreambuf(s, n, s + std::strlen(s))</code>.<sup>329</sup>
  </del></li>
  </ol>
</del></li>
</ol>

<h4><del>D.12.4.2 Member functions [depr.ostrstream.members]</del></h4>
<ol>
<pre><del>strstreambuf* rdbuf() const;</del></pre>
<li><del>
<i>Returns:</i> <code>(strstreambuf*)&amp;sb</code>.
</del></li>

<pre><del>void freeze(bool freezefl = true);</del></pre>
<li><del>
<i>Effects:</i> Calls <code>rdbuf()-&gt;freeze(freezefl)</code>.
</del></li>

<pre><del>char* str();</del></pre>
<li><del>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</del></li>

<pre><del>int pcount() const;</del></pre>
<li><del>
<i>Returns:</i> <code>rdbuf()-&gt;pcount()</code>.
</del></li>
</ol>

<h4><del>D.12.5 Class <code>strstream</code> [depr.strstream]</del></h4>
<pre><del>
namespace std {
  class strstream
    : public basic_iostream&lt;char&gt; {
  public:
    // types
    using char_type = char;
    using int_type  = char_traits&lt;char&gt;::int_type;
    using pos_type  = char_traits&lt;char&gt;::pos_type;
    using off_type  = char_traits&lt;char&gt;::off_type;

    // constructors/destructor
    strstream();
    strstream(char* s, int n,
              ios_base::openmode mode = ios_base::in|ios_base::out);
    virtual ~strstream();

    // members
    strstreambuf* rdbuf() const;
    void freeze(bool freezefl = true);
    int pcount() const;
    char* str();

  private:
    strstreambuf sb;            <i>// exposition only</i>
  };
}
</del></pre>
<ol>
<li><del>
The class <code>strstream</code> supports reading and writing from objects of
class <code>strstreambuf</code>. It supplies a <code>strstreambuf</code> object
to control the associated array object. For the sake of exposition, the
maintained data is presented here as:
  <ol>
  <li><del>
&mdash; <code>sb</code>, the <code>strstreambuf</code> object.
  </del></li>
  </ol>
</del></li>
</ol>

<h4><del>D.12.5.1 <code>strstream</code> constructors [depr.strstream.cons]</del></h4>
<ol>
<pre><del>strstream();</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>iostream(&amp;sb)</code>.
</del></li>

<pre><del>strstream(char* s, int n,
          ios_base::openmode mode = ios_base::in|ios_base::out);</del></pre>
<li><del>
<i>Effects:</i> Initializes the base class with <code>iostream(&amp;sb)</code>,
and <code>sb</code> with one of the two constructors:
  <ol>
  <li><del>
&mdash; If <code>(mode &amp; app) == 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements. The
constructor is <code>strstreambuf(s,n,s)</code>.
  </del></li>
  <li><del>
&mdash; If <code>(mode &amp; app) != 0</code>, then <code>s</code> shall
designate the first element of an array of <code>n</code> elements that
contains an NTBS whose first element is designated by <code>s</code>. The
constructor is <code>strstreambuf(s,n,s + std::strlen(s))</code>.
  </del></li>
  </ol>
</del></li>
</ol>

<h4><del>D.12.5.2 <code>strstream</code> destructor [depr.strstream.dest]</del></h4>
<ol>
<pre><del>virtual ~strstream();</del></pre>
<li><del>
<i>Effects:</i> Destroys an object of class <code>strstream</code>.
</del></li>
</ol>

<h4><del>D.12.5.3 <code>strstream</code> operations [depr.strstream.oper]</del></h4>
<ol>
<pre><del>strstreambuf* rdbuf() const;</del></pre>
<li><del>
<i>Returns:</i> <code>const_cast&lt;strstreambuf*&gt;(&amp;sb)</code>.
</del></li>

<pre><del>void freeze(bool freezefl = true);</del></pre>
<li><del>
<i>Effects:</i> Calls <code>rdbuf()-&gt;freeze(freezefl)</code>.
</del></li>

<pre><del>char* str();</del></pre>
<li><del>
<i>Returns:</i> <code>rdbuf()-&gt;str()</code>.
</del></li>

<pre><del>int pcount() const;</del></pre>
<li><del>
<i>Returns:</i> <code>rdbuf()-&gt;pcount()</code>.
</del></li>
</ol>
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
The main benefit of strstreams is that they provide efficient management of a
shared buffer, reducing much unnecessary copying of data, at the expense of
more user responsibility for managing memory.  Concerns remain about removing
this facility without providing a replacement, such as Peter Sommerlad's
<code>spanstream</code> library that is currently awaiting LWG review for
C++23.  There was no enthusiasm for undeprecating the library at this point,
with clear desire to follow the various paths towards finally removing this
feature after the intended replacement has landed.  It is not clear whether we
would welcome removal in C++23 if the replacement lands in this release, or in
a subsequent standard.  That discussion is deferred to discussions of the
replacement facility itself.
</p>
<p>
Consensus to take no further action on this topic within this omnibus paper.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Take no action at this time.
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.13">Deprecated type traits [depr.meta.types]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
<p>
While traits have been deprecated in earlier versions of the standard,
C++20 removed all traits deprecated in C++17 and earlier, so the traits
that remain were all deprecated by C++20.
</p>
</blockquote>

<p>
The <code>is_pod</code> trait was deprecated by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0767r1">P0767R1</a>
as part of removing the POD vocabulary from the C++ standard, both core and
library.  The term had changed meaning so frequently that it no longer served
as useful vocabulary.  The type trait was extracted to Annex D, and now itself
provides the only definition in the standard for a POD.  Client code is
encouraged to use the more specific traits for trivial and standard layout
types to better describe their need.  Note that the related term POF, for Plain
Old Function, was removed from C++17 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0270r3">P0270R3</a>.
</p>

<p>
The <code>is_pod</code> trait was first supplied as part of C++11, so its
removal would potentially impact programs written against the C++11 standard or
later.  Users have had up to three years of implementations warning on use of
the deprecated trait, so we could consider removal, with the usual proviso that
the name is preserved as a zombie for previous standardization.  As the case
for removal is not urgent, the weak recommendation of this paper is to remove
the trait from C++23.
</p>

<p>
However, the current wording does not follow library best practices, and should
be updated to better specify the <i>Requires</i> clauses with our modern
vocabulary.  The strong recommendation is to retain it as deprecated in Annex D
and revise the wording accordingly.
<p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Clean up wording.
</blockquote>

<blockquote class="note">
Update wording to replace <i>Requires</i> clauses
(see <a href="#3.10">D.10 Requires paragraph</a>).
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove the traits that can live on as zombies.
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li><ins>&mdash; <code>is_pod</code>,</ins></li>
<li><ins>&mdash; <code>is_pod_v</code>,</ins></li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>, and</li>
<li>&mdash; <code>unexpected_handler</code>.</li>
</ol></li>
</ol>

<h4><del>D.13 Deprecated Type Traits [depr.meta.type]</del></h4>
<ol>
<li><del>
The header <code>&lt;type_traits&gt;</code> (20.15.2) has the following additions:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class T&gt; struct is_pod;</del>
  <del>template&lt;class T&gt; inline constexpr bool is_pod_v = is_pod&lt;T&gt;::value;</del>
<del>}</del>
</pre></blockquote>

<li><del>
The behavior of a program that adds specializations for any of the templates
defined in this subclause is undefined, unless explicitly permitted by the
specification of the corresponding template.
</del></li>

<pre><del>template&lt;class T&gt; struct is_pod;</del></pre>
<li><del>
<i>Requires:</i>
<code>remove_all_extents_t&lt;T&gt;</code> shall be a complete type or <i>cv</i> <code>void</code>.
</del></li>

<li><del>
<code>is_pod&lt;T&gt;</code> is a <i>Cpp17UnaryTypeTrait</i> (20.15.1) with a
base characteristic of <code>true_type</code> if <code>T</code> is a POD type,
and <code>false_type</code> otherwise. A POD class is a class that is both a
trivial class and a standard-layout class, and has no non-static data members
of type non-POD class (or array thereof). A POD type is a scalar type, a POD
class, an array of such a type, or a cv-qualified version of one of these
types.
</del></li>

<li><del>
[<i>Note:</i> It is unspecified whether a closure type (7.5.5.1) is a POD type.
<i>&mdash;end note</i>]
</del></li>
</ol>

</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Concerns were raised about the lack of research into how much code is likely to
break with the removal of this API.  We would like to see more numbers and
analysis on publicly available code, such as across all of Github.  Given that
implementers are likely to provide an implementation (through zombie names
freedom) for some time after removal, there was consensus to proceed with
removal, assuming the requested research does not reveal major concerns before
the main LEWG review to follow.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="review_note">
There is a preference for removing replaced facilities from the standard at the
earliest opportunity, and letting the vendors remove the zombie implementations
at a time of their own choosing, assessing their own customer demand.
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.14">Tuple [depr.tuple]</h3>


<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was deprecated as part of the effort to clean up the use and
semantics of <code>volatile</code> in the language, and was adopted by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a>.
It potentially impacts on code written against C++11 and later standards.
</p>

<p>
This feature was deprecated only at the final meeting of the C++20 development
cycle, and at the time this paper is written, there is no experience with how
much code has been impacted by this deprecation.  As such, it is too early to
make any recommendation for a change with respect to this feature.
</p>

<p>
It is further noted that there is a coupling between the deprecated tuple
traits API, and the deprecated support for volatile structured bindings (D.5).
First, note that <code>volatile tuple</code> itself does not support structured
bindings (nor do any <code>pair</code> and <code>array</code>) as there are no
overloads for the <code>get</code> function taking references to
<code>volatile</code> qualified objects.  However, it is still possible for a
user to customize their own type to support such <code>get</code> calls.  If we
remove the <code>volatile</code> support from the tuple traits by default, then
the user would have to provide their own specializations for
<code>tuple_size&lt;volatile TYPE&gt;</code> and
<code>tuple_element&lt;volatile TYPE&gt;</code>, and similarly for the
<code>const volatile</code> qualifier.  Alternatively, we could ensure we
remove the deprecated support for <code>volatile</code> structured bindings at
the same time that we remove the tuple traits <code>volatile</code> API.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
None of the standard library uses these traits, they are not user customizable,
and <code>volatile</code> qualified tuples have no usable member functions or
accessors, so it seems safe to remove these partial specializations at this
point.  The only concern is that the structured bindings core language facility
relies on these specializations for the deprecated <code>volatile</code>
structured bindings feature.  Consensus is that we would like to remove this
feature, contingent on EWG also removing the core support for
<code>volatile</code> structured bindings.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23 if <code>volatile</code> structured bindings are
removed by EWG.
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.15">Variant [depr.variant]</h3>


<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was deprecated as part of the effort to clean up the use and
semantics of <code>volatile</code> in the language, and was adopted by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a>.
It potentially impacts on code written against C++17 and later standards.
</p>

<p>
This feature was deprecated only at the final meeting of the C++20 development
cycle, and at the time this paper is written, there is no experience with how
much code has been impacted by this deprecation. However, <code>variant</code>
has been in the language for a much shorter time than the similarly impacted
<code>tuple</code>, and so it is likely that much less code would be impacted
by its removal.  Secondly, as <code>variant</code> has no <code>volatile</code>
qualified member functions, nor external accessors like <code>get</code>
accepting <code>volatile</code> variants, the scope for reasonable use of a
<code>volatile</code> variant is vanishingly small.  Therefore, the strong
recommendation of this paper is to remove directly from C++23, and the weak
recommendation is to hold it over for one more standard cycle, allowing more
time for any vestigial usage to be reworked.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
remove this feature from C++23.
</blockquote>

<blockquote class="draft_wording">

<h4><del>D.15 Variant [depr.variant]</del></h4>
<ol>
<li><del>
The header <code>&lt;variant&gt;</code> (20.7.2) has the following additions:
</del>
<pre>
<del>namespace std {</del>
  <del>template&lt;class T&gt; struct variant_size&lt;volatile T&gt;;</del>
  <del>template&lt;class T&gt; struct variant_size&lt;const volatile T&gt;;</del>
  <del>template&lt;size_t I, class T&gt; struct variant_alternative&lt;I, volatile T&gt;;</del>
  <del>template&lt;size_t I, class T&gt; struct variant_alternative&lt;I, const volatile T&gt;;</del>
<del>}</del>
</pre>
</li>
<pre>
<del>template&lt;class T&gt; class variant_size&lt;volatile T&gt;;</del>
<del>template&lt;class T&gt; class variant_size&lt;const volatile T&gt;;</del>
</pre>
<li><del>
Let <code>VS</code> denote <code>variant_size&lt;T&gt;</code> of the cv-unqualified type
<code>T</code>. Then specializations of each of the two templates meet the
<i>Cpp17UnaryTypeTrait</i> requirements with a base characteristic of
<code>integral_constant&lt;size_t, VS::value&gt;</code>.
</del></li>
<pre>
<del>template&lt;size_t I, class T&gt; class variant_alternative&lt;I, volatile T&gt;;</del>
<del>template&lt;size_t I, class T&gt; class variant_alternative&lt;I, const volatile T&gt;;</del>
</pre>
<li><del>
Let <code>VA</code> denote <code>variant_alternative&lt;I, T&gt;</code> of the cv-unqualified type <code>T</code>.
Then specializations of each of the two templates meet the
<i>Cpp17TransformationTrait</i> requirements with a member typedef type that names the
following type:
  <ol>
  <li><del>
&mdash; for the first specialization, <code>add_volatile_t&lt;VA::type&gt;</code>, and
  </del></li>
  <li><del>
&mdash; for the second specialization, <code>add_cv_t&lt;VA::type&gt;</code>.
  </del></li>
  </ol>
</del></li>
</ol>

</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
None of the standard library uses these traits, they are not user customizable,
and <code>volatile</code> qualified <code>variant</code>s have no usable member
functions or accessors. Consensus to remove these partial specializations from
C++23.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.16">Deprecated iterator primitives [depr.iterator.primitives]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++17
</blockquote>

<p>
The class template <code>iterator</code> was first deprecated in C++17 by the paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r0">P0174R2</a>.
The concern was that providing the needed support for iterator typenames
through a templated base class, determining which name maps to which type
purely by parameter order, was less clear than simply providing the needed
names.  Further, there were corner cases in usage that fell out of template
syntax that made this tool hard to recommend as a simpler way of providing the
type names, yet that was its whole reason to exist.
</p>
<p>
When this facility was reviewed for removal in C++20, it was noted that there
were valid uses that relied on the default template arguments to deduce at
least a few of the needed type names.  Subsequent work on iterators and ranges
(<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0896r4">P0896R4</a>)
that landed in C++20 now means that work is also done by the primary
<code>iterator_traits</code> template, and so the remaining use case (for new
code) is also covered, making this class template strictly redundant.
</p>
<p>
The main concern that remains is breaking old code by removing this code from
the standard libraries.  That risk is ameliorated by the zombie names clause in
the standard, allowing vendors to maintain their own support for as long as
their customers demand.  By the time C++23 ships, those customers will already
have been on 6 years notice that their code might not be supported in future
standards.  However, we note the repeated use of the name <code>iterator</code>
as a type within many containers means we might choose to leave this name off
the zombie list.  We conservatively place it there anyway, to ensure that we
are covered by the previous standardization terminology to encompass uses other
than as a container iterator typedef.
</p>

<p>
The strong recommendation of this paper is to remove this feature from the
pending standard.  The weak recommendation is to ask what further changes we
would like to see before we could remove this feature.  If there is no
anticipated change of circumstance that would allow the standard to stop
tracking this feature, then the recommendation should be to undeprecate, and
restore this text to the main body of the standard.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
remove this feature from C++23.
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li><ins>&mdash; <code>iterator</code>,</ins></li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>, and</li>
<li>&mdash; <code>unexpected_handler</code>.</li>
</ol></li>
</ol>


<h4><del>D.16 Deprecated iterator primitives [depr.iterator.primitives]</del></h4>
<h4><del>D.16.1 Basic iterator [depr.iterator.basic]</del></h4>
<ol>
<li><del>
The header <code>&lt;iterator&gt;</code> (23.2) has the following addition:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class Category, class T, class Distance = ptrdiff_t,</del>
    <del>class Pointer = T*, class Reference = T&amp;&gt;</del>
  <del>struct iterator {</del>
    <del>using iterator_category = Category;</del>
    <del>using value_type        = T;</del>
    <del>using difference_type   = Distance;</del>
    <del>using pointer           = Pointer;</del>
    <del>using reference         = Reference;</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<li><del>
The <code>iterator</code> template may be used as a base class to ease the
definition of required types for new iterators.
</del></li>

<li><del>
[ <i>Note:</i> If the new iterator type is a class template, then these
aliases will not be visible from within the iterator class's template
definition, but only to callers of that class <i>&mdash; end note</i>]
</del></li>

<li><del>
[ <i>Example:</i> If a C++ program wants to define a bidirectional iterator for
some data structure containing <code>double</code> and such that it works on a
large memory model of the implementation, it can do so with:
<pre>
<del>class MyIterator :</del>
  <del>public iterator&lt;bidirectional_iterator_tag, double, long, T*, T&amp;&gt; {</del>
  <del><i>// code implementing ++, etc.</i></del>
<del>};</del>
</pre>
&mdash; <i>end example</i> ]
</del></li>
</ol>

</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Undeprecate the facility, and restore it to clause 23.
</blockquote>

<blockquote class="note">
Wording to be supplied.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Concerns were raised about the lack of research into how much code is likely to
break with the removal of this API.  We would like to see more numbers and
analysis on publicly available code, such as across all of Github.  The better
treatment of implicit generation of <code>iterator_traits</code> in C++23, and
more familiarity with a limited number of code bases that still rely on this
facility, gave more confidence in moving forward with removal than we had for
C++20.  It was also noted that the name may be unfortunate with the chosen form
of concept naming adopted for C++20, and so its removal might lead to one fewer
sources of future confusion,  Given that implementers are likely to provide an
implementation (through zombie names freedom) for some time after removal,
there was consensus to proceed with removal, assuming the requested research
does not reveal major concerns before the main LEWG review to follow.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.17">Deprecated <code>move_iterator</code> access [depr.move.iter.elem]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was deprecated for C++20 by the paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1252r2">P1252R2</a>
highlighting the concern that for a move iterator adapter, intending to expose
its target as an rvalue (or xvalue), the arrow operator must return the
original adapted iterator, which will likely produce an lvalue when
dereferenced.  The operator is not fit for purpose, and cannot be fixed.  The
workaround for users is to dereference the move iterator with
<code>operator *</code> and call the member they wish to access using the
familiar <code>.</code> notation.  This preserves the value category of the
iterator's target.
</p>

<p>
The proposal for C++20 was to deprecate this operator, with a view to removal
at a later date.  While it may seem early, this is the first such later date
appropriate to consider that removal.
</p>

<p>
Lacking clear evidence that this issue is causing widespread bugs in practice,
the strong recommendation for this paper is to hold the feature in Annex D for
another standard cycle, and strongly consider its removal in C++23.  The weak
recommendation is that with three years (or more) experience of deprecation
warnings, we have given users enough notice, and it is time to remove this
misleading feature now, from C++23.  Code written against the C++11 standard or
later might be impacted by this change.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="draft_wording">
<h4><del>D.17 Deprecated move_iterator access [depr.move.iter.elem]</del></h4>
<ol>
<li>
<del>
The following member is declared in addition to those members specified in 23.5.3.5:
</del>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class Iterator&gt;</del>
    <del>class move_iterator {</del>
    <del>public:</del>
      <del>constexpr pointer operator-&gt;() const;</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>
</li>

<pre><del>constexpr pointer operator-&gt;() const;</del></pre>
<li><del>
<i>Returns:</i> <code>current</code>.
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
<p>
Eric provided the rationale for the ranges reworking removing this overload,
which is that move iterator is supposed to return rvalues, as seen through the
<code>operator*</code> overload returning an rvalue reference, but there is no
way for a pointer to return a pointer-to-rvalue distinct from a pointer-to-lvalue,
and in such cases it is better for this operation to not exist at all.  That is
perfectly in keeping with the revised iterator concepts.  Consensus to proceed
with removal, assuming the subsequent research does not reveal major concerns
before the main LEWG review that is to follow.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.18">Deprecated <code>shared_ptr</code> atomic access [depr.util.smartptr.shared.atomic]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
The legacy C-style atomic API for manipulating shared pointers provided in
C++11 is subtle, frequently misunderstood: a <code>shared_ptr</code> that is to
be used with the atomic API can never be used directly, but can only be
manipulated through the atomic API (other than construction and destruction).
Its failure mode on misuse is silent undefined behavior, typically a data race.
</p>
<p>
C++20 provides a type-safe alternative that also provides support for
<code>atomic&lt;weak_ptr&lt;T&gt;&gt;</code>.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this feature at the earliest opportunity, ideally C++23.
</blockquote>

<blockquote class="draft_wording">
<h4><del>D.18 Deprecated <code>shared_ptr</code> atomic access [depr.util.smartptr.shared.atomic]</del></h4>
<ol>
<li><del>
The header <code>&lt;memory&gt;</code>  (20.10.2) has the following additions:
</del></li>

<blockquote><pre>
<del>namespace std {</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</del>

<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);</del>
<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
<del>template &lt;class T&gt;</del>
  <del>void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
<del>template &lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>

<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>
<del>}</del>
</pre></blockquote>

<li><del>
Concurrent access to a <code>shared_ptr</code> object from multiple threads
does not introduce a data race if the access is done exclusively via the
functions in this section and the instance is passed as their first argument.
</del></li>
<li><del>
The meaning of the arguments of type <code>memory_order</code> is explained in 31.4.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_is_lock_free(const shared_ptr&lt;T&gt;* p);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <code>true</code> if atomic access to <code>*p</code> is lock-free, <code>false</code> otherwise.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load(const shared_ptr&lt;T&gt;* p);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <code>atomic_load_explicit(p, memory_order::seq_cst)</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_load_explicit(const shared_ptr&lt;T&gt;* p, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Requires:</i> <code>mo</code> shall not be <code>memory_order::release</code> or <code>memory_order::acq_rel</code>.
</del></li>
<li><del>
<i>Returns:</i> <code>*p</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>void atomic_store(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Effects:</i> As if by <code>atomic_store_explicit(p, r, memory_order::seq_cst)</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>void atomic_store_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Requires:</i> <code>mo</code> shall not be <code>memory_order::acquire</code> or <code>memory_order::acq_rel</code>.
</del></li>
<li><del>
<i>Effects:</i> As if by <code>p-&gt;swap(r)</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Returns:</i> <code>atomic_exchange_explicit(p, r, memory_order::seq_cst)</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>shared_ptr&lt;T&gt; atomic_exchange_explicit(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt; r, memory_order mo);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Effects:</i> As if by <code>p-&gt;swap(r)</code>.
</del></li>
<li><del>
<i>Returns:</i> The previous value of <code>*p</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null.
</del></li>
<li><del>
<i>Returns:</i>
     <code>atomic_compare_exchange_weak_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)</code>.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>

<blockquote><pre>
<del>template&lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong(shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w);</del>
</pre></blockquote>
<li><del>
<i>Returns:</i>
     <code>atomic_compare_exchange_strong_explicit(p, v, w, memory_order::seq_cst, memory_order::seq_cst)</code>.
</del></li>

<blockquote><pre>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_weak_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>
<del>template &lt;class T&gt;</del>
  <del>bool atomic_compare_exchange_strong_explicit(</del>
    <del>shared_ptr&lt;T&gt;* p, shared_ptr&lt;T&gt;* v, shared_ptr&lt;T&gt; w,</del>
    <del>memory_order success, memory_order failure);</del>
</pre></blockquote>
<li><del>
<i>Requires:</i> <code>p</code> shall not be null and <code>v</code> shall not be null.
The <code>failure</code> argument shall not be <code>memory_order::release</code> nor
<code>memory_order::acq_rel</code>.
</del></li>
<li><del>
<i>Effects:</i> If <code>*p</code> is equivalent to <code>*v</code>, assigns <code>w</code>
to <code>*p</code> and has synchronization semantics corresponding to the value of
<code>success</code>, otherwise assigns <code>*p</code> to <code>*v</code> and has synchronization semantics
corresponding to the value of <code>failure</code>.
</del></li>
<li><del>
<i>Returns:</i> <code>true</code> if <code>*p</code> was equivalent to <code>*v</code>, <code>false</code> otherwise.
</del></li>
<li><del>
<i>Throws:</i> Nothing.
</del></li>
<li><del>
<i>Remarks:</i> Two <code>shared_ptr</code> objects are equivalent if they store
the same pointer value and share ownership. The weak form may fail spuriously.
See 31.8.1.
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature at the earliest opportunity <i>after</i> C++23.
</blockquote>

<blockquote class="note">
Update wording to replace <i>Requires</i> clauses (see <a href="#3.10">D.10 Requires paragraph</a>).
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
This topic was immediately deferred to SG1 for initial review, before coming
back to this group.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Defer to SG1
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.19">Deprecated <code>basic_string</code> capacity [depr.string.capacity]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was first deprecated for C++20 by the paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0966r1">P0966R1</a>.
The deprecation was a consequence of cleaning up the behavior of the
<code>reserve</code> function to no longer optionally reallocate on a request
to shrink.  The original C++98 specification for <code>basic_string</code>
supplied a default argument of 0 for <code>reserve</code>, turning a call to
<code>reserve()</code> into a non-binding <code>shrink_to_fit</code> request.
Note that <code>shrink_to_fit</code> was added in C++11 to better support this
use case.  With the removal of the potentially reallocating behavior,
<code>reserve()</code> is now a redundant function overload that is guaranteed
to do nothing.  Hence it was deprecated in C++20, with a view to removing it
entirely in a later standard to eliminate on more legacy source of confusion
from the standard.
</p>

<p>
As the feature was deprecated so recently, the strong recommendation of this
paper is to make no changes for C++23, but strongly consider removal when it is
time to review again for C++26.  The weak recommendation is that this feature
is small and obscure enough that it is better to remove now from C++23 than
preserve for another three years into C++26.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="draft_wording">
<h4><del>D.19 Deprecated basic_string capacity [depr.string.capacity]</del></h4>
<ol>
<li><del>
 The following member is declared in addition to those members specified in 21.3.2.4:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class charT, class traits = char_traits&lt;charT&gt;,</del>
                <del>class Allocator = allocator&lt;charT&gt;&gt;</del>
   <del>class basic_string {</del>
   <del>public:</del>
     <del>void reserve();</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<pre><del>void reserve();</del></pre>
<li><del>
<i>Effects:</i> After this call, <code>capacity()</code> has an unspecified value greater
than or equal to <code>size()</code>. [<i>Note:</i> This is a non-binding shrink to fit
request. <i>&mdash;end note</i>]
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
General agreement that this member is a holdover from another time, whose
replacement has been in place for some time.  Consensus to remove from C++23,
assuming the subsequent research does not reveal major concerns before the main
LEWG review that is to follow.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove this feature from C++23
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.20">Deprecated Standard code conversion facets [depr.locale.stdcvt]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++17
</blockquote>

<p>
This feature was originally proposed for C++11 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2007">N2007</a>
and deprecated for C++17 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0">P0618R0</a>.
As noted at the time, the feature was underspecified and would require more
work than we wished to invest to bring it up to standard. Since then SG16 has
been convened and is producing a steady stream of work to bring reliable
well-specified Unicode support to C++.
</p>
<p>
It should also be noted that this deprecated clause pins a dated reference to a
20 year old ISO standard (revised repeatedly over the intervening decades)
purely to provide a definition of the term UCS2.
</p>
<p>
Given vendors propensity to provide ongoing support for these names under the
zombie name reservations, the strong recommendation of this paper is to remove
this library immediately from C++23, along with its binding reference to an
obsolete Unicode standard.  The weak recommendation is to do nothing at this
point, until SG16 (or some other entity) produces a clean replacement for this
facility.
</p>
<p>
We note that this feature was originally added at the Kona 2007 meeting so that
(while motivated by likely user applications) the example in the then recently
added [lib.conversions] called on standard rather than user-provided classes to
illustrate use (adopted just one meeting earlier).  Therefore, if we remove
this library unilaterally, we should also revert that example back to its
original spelling.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this facility from the standard at the earliest opportunity.
</blockquote>

<blockquote class="draft_wording">
<h4>2 Normative references [intro.refs]</h4>
<ol>
<li>
The following documents are referred to in the text in such a way that some or
all of their content constitutes requirements of this document. For dated
references, only the edition cited applies. For undated references, the latest
edition of the referenced document (including any amendments) applies.
  <ol>
  <li>
&mdash; Ecma International, ECMAScript Language Specification, Standard Ecma-262, third edition, 1999.
  </li>
  <li>
&mdash; ISO/IEC 2382 (all parts), Information technology — Vocabulary
  </li>
  <li>
&mdash; ISO 8601:2004, Data elements and interchange formats — Information interchange — Representation of dates and times
  </li>
  <li>
&mdash; ISO/IEC 9899:2018, Programming languages — C
  </li>
  <li>
&mdash; ISO/IEC 9945:2003, Information Technology — Portable Operating System Interface (POSIX)
  </li>
  <li>
&mdash; ISO/IEC 10646, Information technology — Universal Coded Character Set (UCS)
  </li>
  <li><del>
&mdash; ISO/IEC 10646-1:1993, Information technology — Universal Multiple-Octet Coded Character Set (UCS) — Part 1: Architecture and Basic Multilingual Plane
  </del></li>
  <li>
&mdash; ISO/IEC/IEEE 60559:2011, Information technology — Microprocessor Systems — Floating-Point arithmetic
  </li>
  <li>
&mdash; ISO 80000-2:2009, Quantities and units — Part 2: Mathematical signs and symbols to be used in the natural sciences and technology
  </li>
  </ol>
</li>
<li>
The library described in Clause 7 of ISO/IEC 9899:2018 is hereinafter called
the C standard library.<sup>1</sup>
</li>
<li>
The operating system interface described in ISO/IEC 9945:2003 is hereinafter
called POSIX.
</li>
<li>
The ECMAScript Language Specification described in Standard Ecma-262 is hereinafter called ECMA-262.
</li>
<li><del>
[Note: References to ISO/IEC 10646-1:1993 are used only to support deprecated features (D.19). — end note ]
</del></li>
</ol>

<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li><ins>&mdash; <code>codecvt_mode</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf16</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf8</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf8_utf16</code>,</ins></li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li><ins>&mdash; <code>consume_header</code>,</ins></li>
<li><ins>&mdash; <code>generate_header</code>,</ins></li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li><ins>&mdash; <code>little_endian</code>,</ins></li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>, and</li>
<li>&mdash; <code>unexpected_handler</code>.</li>
</ol>
</li>
<li>
The following names are reserved as member types for previous standardization,
and may not be used as a name for object-like macros in portable code:
  <ol>
  <li>&mdash; <code>argument_type</code>,</li>
  <li>&mdash; <code>first_argument_type</code>,</li>
  <li>&mdash; <code>io_state</code>,</li>
  <li>&mdash; <code>open_mode</code>,</li>
  <li>&mdash; <code>second_argument_type</code>, and</li>
  <li>&mdash; <code>seek_dir</code>.</li>
  </ol>
</li>
<li>
The name <code>stossc</code> is reserved as a member function for previous
standardization, and may not be used as a name for function-like macros in
portable code.
</li>
<li>
The header names
<code>&lt;ccomplex&gt;</code>,
<code>&lt;ciso646&gt;</code>,
<ins><code>&lt;codecvt&gt;</code>,</ins>
<code>&lt;cstdalign&gt;</code>,
<code>&lt;cstdbool&gt;</code>, and
<code>&lt;ctgmath&gt;</code> are reserved for previous
standardization.
</li>

</ol>

<h4><del>D.20 Deprecated Standard code conversion facets [depr.locale.stdcvt]</del></h4>
<ol>
<li><del>
The header <code>&lt;codecvt&gt;</code> provides code conversion facets for various
character encodings.
</del></li>
</ol>
<h4><del>D.20.1 Header <code>&lt;codecvt&gt;</code> synopsis [depr.codecvt.syn]</del></h4>
<blockquote><pre>
<del>namespace std {</del>
  <del>enum codecvt_mode {</del>
    <del>consume_header = 4,</del>
    <del>generate_header = 2,</del>
    <del>little_endian = 1</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf8</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf8(size_t refs = 0);</del>
    <del>~codecvt_utf8();</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf16</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf16(size_t refs = 0);</del>
    <del>~codecvt_utf16();</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf8_utf16</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf8_utf16(size_t refs = 0);</del>
    <del>~codecvt_utf8_utf16();</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<h4><del>D.20.2 Requirements [depr.locale.stdcvt.req]</del></h4>
<ol>
<li><del>
For each of the three code conversion facets <code>codecvt_utf8</code>,
<code>codecvt_utf16</code>, and <code>codecvt_utf8_utf16</code>:
  <ol>
<li><del>
&mdash; <code>Elem</code> is the wide-character type, such as <code>wchar_t</code>,
<code>char16_t</code>, or <code>char32_t</code>.
</del></li>
<li><del>
&mdash; <code>Maxcode</code> is the largest wide-character code that the facet will
read or write without reporting a conversion error.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; consume_header)</code>, the facet shall consume an
initial header sequence, if present, when reading a multibyte sequence to
determine the endianness of the subsequent multibyte sequence to be read.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; generate_header)</code>, the facet shall generate an
initial header sequence when writing a multibyte sequence to advertise the
endianness of the subsequent multibyte sequence to be written.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; little_endian)</code>, the facet shall generate a
multibyte sequence in little-endian order, as opposed to the default big-endian
order.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf8</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-8 multibyte sequences and UCS2 or
UTF-32 (depending on the size of <code>Elem</code>) within the program.
</del></li>
<li><del>
&mdash; Endianness shall not affect how multibyte sequences are read or written.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written as either a text or a binary file.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf16</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-16 multibyte sequences and UCS2 or
UTF-32 (depending on the size of <code>Elem</code>) within the program.
</del></li>
<li><del>
&mdash; Multibyte sequences shall be read or written according to the
<code>Mode</code> flag, as set out above.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written only as a binary file.
Attempting to write to a text file produces undefined behavior.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf8_utf16</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-8 multibyte sequences and UTF-16
(one or two 16-bit codes) within the program.
</del></li>
<li><del>
&mdash; Endianness shall not affect how multibyte sequences are read or written.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written as either a text or a binary file.
</del></li>
  </ol>
</del></li>

<li><del>
The encoding forms UTF-8, UTF-16, and UTF-32 are specified in ISO/IEC 10646.
The encoding form UCS-2 is specified in ISO/IEC 10646-1:1993.
</del></li>
</ol>

<h4>D.21.1 Class template wstring_convert [depr.conversions.string]</h4>
<ol>
<li>
Class template <code>wstring_convert</code> performs conversions between a wide
string and a byte string.  It lets you specify a code conversion facet (like
class template <code>codecvt</code>) to perform the conversions, without
affecting any streams or locales.  [ <i>Example:</i>  If you <del>want to use
the code conversion facet <code>codecvt_utf8</code></del> <ins>have a code
conversion facet named <code>codecvt_utf8</code> that you want to use</ins> to
output to <code>cout</code> a UTF-8 multibyte sequence corresponding to a wide
string, but you don’t want to alter the locale for <code>cout</code>, you can
write something like:
<blockquote><pre>
<ins>std::</ins>wstring_convert&lt;<del>std::</del>codecvt_utf8&lt;wchar_t&gt;&gt; myconv;
std::string mbstring = myconv.to_bytes(L"Hello\n");
std::cout &lt;&lt; mbstring;
</pre></blockquote>
&mdash; <i>end example</i> ]
</li>
</ol>

</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
take no action at this time.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Agreement that this feature does not work well today, is underspecified, and
dragging in a normative reference to withdrawn ISO documents.  Any fix coming
out of SG16 will be an entirely new facility, not a rehabilitation of this
header.  Consensus to remove this library from C++23.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Remove from C++23.
</blockquote>

<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.21">Deprecated convenience conversions [depr.conversions]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++17
</blockquote>

<p>
This feature was originally proposed for C++11 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2401">N2401</a>
and deprecated for C++17 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0">P0618R0</a>.
As noted at the time, the feature was underspecified and would require more
work than we wished to invest to bring it up to standard. Since then SG16 has
been convened and is producing a steady stream of work to bring reliable
well-specified Unicode support to C++.
</p>
<p>
Given vendors propensity to provide ongoing support for these names under the
zombie name reservations, the strong recommendation of this paper is to remove
this library immediately from the C++23 standard.  The weak recommendation is
to do the minimal work to clean up the wording to use the more precise terms
that replaced <i>Requires</i> clauses, waiting until SG16 (or some other
entity) produces a clean replacement for this facility for users to migrate to
before removal.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Remove this facility from the standard at the earliest opportunity.
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>,<del> and</del></li>
<li>&mdash; <code>unexpected_handler</code><del>.</del><ins>,</ins></li>
<li><ins>&mdash; <code>wbuffer_convert</code>, and</ins></li>
<li><ins>&mdash; <code>wstring_convert</code>.</ins></li>
</ol>
</li>
<li>
The following names are reserved as member types for previous standardization,
and may not be used as a name for object-like macros in portable code:
  <ol>
<li>&mdash; <code>argument_type</code>,
<li>&mdash; <code>first_argument_type</code>,
<li>&mdash; <code>io_state</code>,
<li>&mdash; <code>open_mode</code>,
<li>&mdash; <code>second_argument_type</code>, and
<li>&mdash; <code>seek_dir</code>.
  </ol>
</li>
<li>
<del>The name <code>stossc</code> is reserved as a member function for previous
standardization, and may not be used as a name for function-like macros in
portable code.</del>
<ins>The following names are reserved as member functions for previous
standardization, and may not be used as a name for function-like macros in
portable code:</ins>
  <ol>
  <li><ins>&mdash; <code>converted</code>,</ins></li>
  <li><ins>&mdash; <code>from_bytes</code>,</ins></li>
  <li><ins>&mdash; <code>stossc</code>, and</ins></li>
  <li><ins>&mdash; <code>to_bytes</code>.</ins></li>
  </ol>
</li>
<li>
The header names
<code>&lt;ccomplex&gt;</code>,
<code>&lt;ciso646&gt;</code>,
<code>&lt;cstdalign&gt;</code>,
<code>&lt;cstdbool&gt;</code>, and
<code>&lt;ctgmath&gt;</code> are reserved for previous
standardization.
</li>
</ol>

<h4><del>D.21 Deprecated convenience conversion interfaces [depr.conversions]</del></h4>
<ol>
<li><del>
The header <code>&lt;locale&gt;</code> (28.2) has the following additions:
</del></li>
<pre><blockquote>
<del>namespace std {</del>
  <del>template&lt;class Codecvt, class Elem = wchar_t,</del>
           <del>class WideAlloc = allocator&lt;Elem&gt;,</del>
           <del>class ByteAlloc = allocator&lt;char&gt;&gt;</del>
    <del>class wstring_convert;</del>
  <del>template&lt;class Codecvt, class Elem = wchar_t,</del>
           <del>class Tr = char_traits&lt;Elem&gt;</del>
    <del>class wbuffer_convert;</del>
<del>}</del>
</blockquote></pre>
</ol>

<h4><del>D.21.1 Class template wstring_convert [depr.conversions.string]</del></h4>
<ol>
<li><del>
Class template <code>wstring_convert</code> performs conversions between a wide
string and a byte string.  It lets you specify a code conversion facet (like
class template <code>codecvt</code>) to perform the conversions, without
affecting any streams or locales.  [ <i>Example:</i> If you want to use the
code conversion facet <code>codecvt_utf8</code> to output to <code>cout</code>
a UTF-8 multibyte sequence corresponding to a wide string, but you don’t want
to alter the locale for <code>cout</code>, you can write something like:
<blockquote><pre>
<del>wstring_convert&lt;std::codecvt_utf8&lt;wchar_t&gt;&gt; myconv;</del>
<del>std::string mbstring = myconv.to_bytes(L"Hello\n");</del>
<del>std::cout &lt;&lt; mbstring;</del>
</pre></blockquote>
&mdash; <i>end example</i> ]
</del></li>

<pre><blockquote>
<del>namespace std {</del>
<del>template &lt;class Codecvt, class Elem = wchar_t,</del>
          <del>class WideAlloc = allocator&lt;Elem&gt;,</del>
          <del>class ByteAlloc = allocator&lt;char&gt;&gt;</del>
  <del>class wstring_convert {</del>
  <del>public:</del>
    <del>using byte_string = basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;;</del>
    <del>using wide_string = basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;;</del>
    <del>using state_type  = typename Codecvt::state_type;</del>
    <del>using int_type    = typename wide_string::traits_type::int_type;</del>

    <del>wstring_convert() : wstring_convert(new Codecvt) {}</del>
    <del>explicit wstring_convert(Codecvt* pcvt = new Codecvt);</del>
    <del>wstring_convert(Codecvt* pcvt, state_type state);</del>
    <del>explicit wstring_convert(const byte_string&amp; byte_err,</del>
                             <del>const wide_string&amp; wide_err = wide_string());</del>
    <del>~wstring_convert();</del>

    <del>wstring_convert(const wstring_convert&amp;) = delete;</del>
    <del>wstring_convert&amp; operator=(const wstring_convert&amp;) = delete;</del>

    <del>wide_string from_bytes(char byte);</del>
    <del>wide_string from_bytes(const char* ptr);</del>
    <del>wide_string from_bytes(const byte_string&amp; str);</del>
    <del>wide_string from_bytes(const char* first, const char* last);</del>

    <del>byte_string to_bytes(Elem wchar);</del>
    <del>byte_string to_bytes(const Elem* wptr);</del>
    <del>byte_string to_bytes(const wide_string&amp; wstr);</del>
    <del>byte_string to_bytes(const Elem* first, const Elem* last);</del>

    <del>size_t converted() const noexcept;</del>
    <del>state_type state() const;</del>

  <del>private:</del>
    <del>byte_string byte_err_string;  <i>// Exposition only</i></del>
    <del>wide_string wide_err_string;  <i>// Exposition only</i></del>
    <del>Codecvt* cvtptr;              <i>// Exposition only</i></del>
    <del>state_type cvtstate;          <i>// Exposition only</i></del>
    <del>size_t cvtcount;              <i>// Exposition only</i></del>
  <del>};</del>
<del>}</del>
</blockquote></pre>

<li><del>
The class template describes an object that controls conversions between wide
string objects of class
<code>basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;</code> and
byte string objects of class
<code>basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;</code>.
The class template defines the types <code>wide_string</code> and
<code>byte_string</code> as synonyms for these two types. Conversion between a
sequence of <code>Elem</code> values (stored in a <code>wide_string</code>
object) and multibyte sequences (stored in a <code>byte_string</code> object)
is performed by an object of class <code>Codecvt</code>, which meets the
requirements of the standard code-conversion facet
<code>codecvt&lt;Elem, char, mbstate_t&gt;</code>.
</del></li>
<li><del>
An object of this class template stores:
  <ol>
  <li><del>
  &mdash; <code>byte_err_string</code> &mdash; a byte string to display on errors
  </del></li>
  <li><del>
  &mdash; <code>wide_err_string</code> &mdash; a wide string to display on errors
  </del></li>
  <li><del>
  &mdash; <code>cvtptr</code> &mdash; a pointer to the allocated conversion object
  (which is freed when the <code>wstring_convert</code> object is destroyed)
  </del></li>
  <li><del>
  &mdash; <code>cvtstate</code> &mdash; a conversion state object
  </del></li>
  <li><del>
  &mdash; <code>cvtcount</code> &mdash; a conversion count
  </del></li>
  </ol>
</del></li>

<pre><blockquote>
<del>using byte_string = basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;;</del>
</blockquote></pre>
<li><del>
The type shall be a synonym for
<code>basic_string&lt;char, char_traits&lt;char&gt;, ByteAlloc&gt;</code>
</del></li>

<pre><blockquote>
<del>size_t converted() const noexcept;</del>
</blockquote></pre>
<li><del>
<i>Returns:</i> <code>cvtcount</code>.
</del></li>

<pre><blockquote>
<del>wide_string from_bytes(char byte);</del>
<del>wide_string from_bytes(const char* ptr);</del>
<del>wide_string from_bytes(const byte_string&amp; str);</del>
<del>wide_string from_bytes(const char* first, const char* last);</del>
</blockquote></pre>
<li><del>
<i>Effects:</i> The first member function shall convert the single-element
sequence <code>byte</code> to a wide string. The second member function shall
convert the null-terminated sequence beginning at <code>ptr</code> to a wide
string. The third member function shall convert the sequence stored in
<code>str</code> to a wide string. The fourth member function shall convert the
sequence defined by the range <code>[first, last)</code> to a wide string.
</del></li>
<li><del>
In all cases:
  <ol>
  <li><del>
&mdash; If the <code>cvtstate</code> object was not constructed with an explicit
value, it shall be set to its default value (the initial conversion state)
before the conversion begins. Otherwise it shall be left unchanged.
  </del></li>
  <li><del>
&mdash; The number of input elements successfully converted shall be stored in
<code>cvtcount</code>.
  </del></li>
  </ol>
</del></li>

<li><del>
<i>Returns:</i> If no conversion error occurs, the member function shall return
the converted wide string. Otherwise, if the object was constructed with a
wide-error string, the member function shall return the wide-error string.
Otherwise, the member function throws an object of class <code>range_error</code>.
</del></li>

<pre><blockquote>
<del>using int_type = typename wide_string::traits_type::int_type;</del>
</blockquote></pre>
<li><del>
The type shall be a synonym for <code>wide_string::traits_type::int_type</code>.
</del></li>

<pre><blockquote>
<del>state_type state() const;</del>
</blockquote></pre>
<li><del>
returns <code>cvtstate</code>.
</del></li>

<pre><blockquote>
<del>using state_type = typename Codecvt::state_type;</del>
</blockquote></pre>
<li><del>
The type shall be a synonym for <code>Codecvt::state_type</code>.
</del></li>

<pre><blockquote>
<del>byte_string to_bytes(Elem wchar);</del>
<del>byte_string to_bytes(const Elem* wptr);</del>
<del>byte_string to_bytes(const wide_string&amp; wstr);</del>
<del>byte_string to_bytes(const Elem* first, const Elem* last);</del>
</blockquote></pre>
<li><del>
<i>Effects:</i> The first member function shall convert the single-element
sequence <code>wchar</code> to a byte string. The second member function shall
convert the null-terminated sequence beginning at <code>wptr</code> to a byte
string. The third member function shall convert the sequence stored in
<code>wstr</code> to a byte string. The fourth member function shall convert
the sequence defined by the range <code>[first, last)</code> to a byte string.
</del></li>

<li><del>
In all cases:
  <ol>
  <li><del>
&mdash; If the <code>cvtstate</code> object was not constructed with an explicit
value, it shall be set to its default value (the initial conversion state)
before the conversion begins. Otherwise it shall be left unchanged.
  </del></li>
  <li><del>
&mdash; The number of input elements successfully converted shall be stored in
<code>cvtcount</code>.
  </del></li>
  </ol>
</del></li>

<li><del>
<i>Returns:</i> If no conversion error occurs, the member function shall return
the converted byte string. Otherwise, if the object was constructed with a
byte-error string, the member function shall return the byte-error string.
Otherwise, the member function shall throw an object of class
<code>range_error</code>.
</del></li>

<pre><blockquote>
<del>using wide_string = basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;;</del>
</blockquote></pre>
<li><del>
The type shall be a synonym for
<code>basic_string&lt;Elem, char_traits&lt;Elem&gt;, WideAlloc&gt;</code>.
</del></li>

<pre><blockquote>
<del>explicit wstring_convert(Codecvt* pcvt = new Codecvt);</del>
<del>wstring_convert(Codecvt* pcvt, state_type state);</del>
<del>explicit wstring_convert(const byte_string&amp; byte_err,</del>
    <del>const wide_string&amp; wide_err = wide_string());</del>
</blockquote></pre>
<li><del>
<i>Requires:</i> For the first and second constructors, <code>pcvt != nullptr</code>.
</del></li>

<li><del>
<i>Effects:</i> The first constructor shall store <code>pcvt</code> in
<code>cvtptr</code> and default values in <code>cvtstate</code>,
<code>byte_err_string</code>, and <code>wide_err_string</code>. The second
constructor shall store <code>pcvt</code> in <code>cvtptr</code>,
<code>state</code> in <code>cvtstate</code>, and default values in
<code>byte_err_string</code> and <code>wide_err_string</code>; moreover the
stored state shall be retained between calls to <code>from_bytes</code> and
<code>to_bytes</code>. The third constructor shall store <code>new
Codecvt</code> in <code>cvtptr</code>, <code>state_type()</code> in
<code>cvtstate</code>, <code>byte_err</code> in <code>byte_err_string</code>,
and <code>wide_err</code> in <code>wide_err_string</code>.
</del></li>

<pre><blockquote>
<del>~wstring_convert();</del>
</blockquote></pre>
<li><del>
<i>Effects:</i> The destructor shall delete <code>cvtptr</code>.
</del></li>
</ol>


<h4><del>D.21.2 Class template wbuffer_convert [depr.conversions.buffer]</del></h4>
<ol>
<li><del>
Class template <code>wbuffer_convert</code> looks like a wide stream buffer,
but performs all its I/O through an underlying byte stream buffer that you
specify when you construct it. Like class template
<code>wstring_convert</code>, it lets you specify a code conversion facet to
perform the conversions, without affecting any streams or locales.
</del></li>
<pre><blockquote>
<del>namespace std {</del>
<del>template &lt;class Codecvt, class Elem = wchar_t, class Tr = char_traits&lt;Elem&gt;&gt;</del>
  <del>class wbuffer_convert</del>
    <del>: public basic_streambuf&lt;Elem, Tr&gt; {</del>
  <del>public:</del>
    <del>using state_type = typename Codecvt::state_type;</del>

    <del>wbuffer_convert() : wbuffer_convert(nullptr) {}</del>
    <del>explicit wbuffer_convert(streambuf* bytebuf = 0,</del>
                             <del>Codecvt* pcvt = new Codecvt,</del>
                             <del>state_type state = state_type());</del>

    <del>~wbuffer_convert();</del>

    <del>wbuffer_convert(const wbuffer_convert&amp;) = delete;</del>
    <del>wbuffer_convert&amp; operator=(const wbuffer_convert&amp;) = delete;</del>

    <del>streambuf* rdbuf() const;</del>
    <del>streambuf* rdbuf(streambuf* bytebuf);</del>

    <del>state_type state() const;</del>

  <del>private:</del>
    <del>streambuf* bufptr;        // exposition only</del>
    <del>Codecvt* cvtptr;          // exposition only</del>
    <del>state_type cvtstate;      // exposition only</del>
  <del>};</del>
<del>}</del>
</blockquote></pre>
<li><del>
The class template describes a stream buffer that controls the transmission of
elements of type <code>Elem</code>, whose character traits are described by the
class <code>Tr</code>, to and from a byte stream buffer of type
<code>streambuf</code>.  Conversion between a sequence of <code>Elem</code>
values and multibyte sequences is performed by an object of class
<code>Codecvt</code>, which shall meet the requirements of the standard
code-conversion facet <code>codecvt&lt;Elem, char, mbstate_t&gt;</code>.
</del></li>

<li><del>
An object of this class template stores:
  <ol>
  <li><del>
&mdash; <code>bufptr</code> &mdash; a pointer to its underlying byte stream buffer
  </del></li>
  <li><del>
&mdash; <code>cvtptr</code> &mdash; a pointer to the allocated conversion object
(which is freed when the <code>wbuffer_convert</code> object is destroyed)
  </del></li>
  <li><del>
&mdash; <code>cvtstate</code> &mdash; a conversion state object
  </del></li>
  </ol>
</del></li>

<pre><blockquote>
<del>state_type state() const;</del>
</blockquote></pre>
<li><del>
<i>Returns:</i> <code>cvtstate</code>.
</del></li>

<pre><blockquote>
<del>streambuf* rdbuf() const;</del>
</blockquote></pre>
<li><del>
<i>Returns:</i> <code>bufptr</code>.
</del></li>

<pre><blockquote>
<del>streambuf* rdbuf(streambuf* bytebuf);</del>
</blockquote></pre>
<li><del>
<i>Effects:</i> Stores <code>bytebuf</code> in <code>bufptr</code>.
</del></li>
<li><del>
<i>Returns:</i> The previous value of <code>bufptr</code>.
</del></li>

<pre><blockquote>
<del>using state_type = typename Codecvt::state_type;</del>
</blockquote></pre>
<li><del>
The type shall be a synonym for <code>Codecvt::state_type</code>.
</del></li>

<pre><blockquote>
<del>explicit wbuffer_convert(streambuf* bytebuf = 0,</del>
    <del>Codecvt* pcvt = new Codecvt, state_type state = state_type());</del>
</blockquote></pre>
<li><del>
<i>Requires:</i> <code>pcvt != nullptr</code>.
</del></li>
<li><del>
<i>Effects:</i> The constructor constructs a stream buffer object, initializes
<code>bufptr</code> to <code>bytebuf</code>, initializes <code>cvtptr</code> to
<code>pcvt</code>, and initializes <code>cvtstate</code> to <code>state</code>.
</del></li>

<pre><blockquote>
<del>~wbuffer_convert();</del>
</blockquote></pre>

<li><del>
<i>Effects:</i> The destructor shall delete <code>cvtptr</code>.
</del></li>
</ol>

</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Clean up wording.
</blockquote>

<blockquote class="note">
Update wording to replace <i>Requires</i> clauses (see <a href="#3.10">D.10 Requires paragraph</a>).
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Discussion was broadly in favor of removal from the C++23 specification, and
relying on library vendors to maintain source compatibility as long as needed.
However, LEWGI explicitly requested to confer with SG16 in case that study
group is aware of any reason to hold back on removal, before proceeding with
the recommendation.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Check with SG16 for any concerns; otherwise remove this feature from C++23
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.22">Deprecated locale category facets [depr.locale.category]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
This feature was added as part of the initial basic support for Unicode types
in C++11 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2238">N2238</a>
and deprecated on the recommendation of SG16 for C++20 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6">P0482R6</a>.
</p>

<p>
As SG16 do not report any urgent issue relating to this deprecated feature, and
are still working through the process of providing clean Unicode support in the
C++ standard library, and given the deprecation is as recent as C++20, both the
strong and weak recommendations are to take no action on this feature at this
time.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>

<blockquote class="recommend">
<b>Weak recommendation:</b>
Take no action.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Discussion was broadly in favor of removal from the C++23 specification, and
relying on library vendors to maintain source compatibility as long as needed.
However, LEWGI explicitly requested to confer with SG16 in case that study
group is aware of any reason to hold back on removal, before proceeding with
the recommendation.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Check with SG16 for any concerns; otherwise remove this feature from C++23
</blockquote>

<blockquote class="draft_wording">
<h4><del>D.22 Deprecated locale category facets [depr.locale.category]</del></h4>
<ol>
<li>
<del>The <code>ctype</code> locale category includes the following facets as if they were specified in table Table 100 of 28.3.1.1.1.</del>
<pre>
<del>codecvt&lt;char16_t, char, mbstate_t&gt;</del>
<del>codecvt&lt;char32_t, char, mbstate_t&gt;</del>
</pre>
</li>
<li>
<del>The <code>ctype</code> locale category includes the following facets as if they were specified in table Table 101 of 28.3.1.1.1.</del>
<pre>
<del>codecvt_byname&lt;char16_t, char, mbstate_t&gt;</del>
<del>codecvt_byname&lt;char32_t, char, mbstate_t&gt;</del>
</pre>
</li>
<li><del>
The following class template specializations are required in addition to those
specified in 28.4.1.4. The specialization <code>codecvt&lt;char16_t, char,
mbstate_t&gt;</code> converts between the UTF-16 and UTF-8 encoding forms, and
the specialization <code>codecvt&lt;char32_t, char, mbstate_t&gt;</code> converts
between the UTF-32 and UTF-8 encoding forms.
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>



<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.23">Deprecated filesystem path factory functions [depr.fs.path.factory]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
A factory function to create path names from UTF-8 sequences was part of the
original filesystem library adopted for C++17.  However, this was the only
string-based factory function, as the preferred interface is to simply
construct a <code>path</code> with a string of the corresponding type/encoding.
This factory function was deprecated in C++20 with the addition of
<code>char8_t</code> and the ability to now invoke a specific constructor for
UTF-8 encoded (and typed) strings.  See
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6">P0482R6</a>
for details.
</p>
<p>
The legacy API continues to function, but is more cumbersome than necessary.
There appears to be no compelling case that the API is a risk through misuse.
Therefore, given it was so recently deprecated, the strong recommendation is to
retain this feature in Annex D for C++23, giving the community time to catch
up, and consider removal again for C++26.  However, the current wording does
not follow library best practices, and should be updated to better specify the
<i>Requires</i> clauses.
</p>
<p>
However, while it does no active harm, there is always a cost to maintaining
text in the standard.  The application of zombie names means that even if we
remove this clause from Annex D in C++23, standard library vendors are likely
to continue shipping to meet customer demand for some time to come.  So the
weak recommendation is to add the names to the zombie clause, and remove
immediately from C++23.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Clean up wording.
</blockquote>

<blockquote class="note">
Update wording to replace <i>Requires</i> clauses (see <a href="#3.10">D.10 Requires paragraph</a>).
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove this feature from C++23
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>— <code>auto_ptr</code>,</li>
<li>— <code>auto_ptr_ref</code>,</li>
<li>— <code>binary_function</code>,</li>
<li>— <code>binary_negate</code>,</li>
<li>— <code>bind1st</code>,</li>
<li>— <code>bind2nd</code>,</li>
<li>— <code>binder1st</code>,</li>
<li>— <code>binder2nd</code>,</li>
<li>— <code>const_mem_fun1_ref_t</code>,</li>
<li>— <code>const_mem_fun1_t</code>,</li>
<li>— <code>const_mem_fun_ref_t</code>,</li>
<li>— <code>const_mem_fun_t</code>,</li>
<li>— <code>get_temporary_buffer</code>,</li>
<li>— <code>get_unexpected</code>,</li>
<li>— <code>gets</code>,</li>
<li>— <code>is_literal_type</code>,</li>
<li>— <code>is_literal_type_v</code>,</li>
<li>— <code>mem_fun1_ref_t</code>,</li>
<li>— <code>mem_fun1_t</code>,</li>
<li>— <code>mem_fun_ref_t</code>,</li>
<li>— <code>mem_fun_ref</code>,</li>
<li>— <code>mem_fun_t</code>,</li>
<li>— <code>mem_fun</code>,</li>
<li>— <code>not1</code>,</li>
<li>— <code>not2</code>,</li>
<li>— <code>pointer_to_binary_function</code>,</li>
<li>— <code>pointer_to_unary_function</code>,</li>
<li>— <code>ptr_fun</code>,</li>
<li>— <code>random_shuffle</code>,</li>
<li>— <code>raw_storage_iterator</code>,</li>
<li>— <code>result_of</code>,</li>
<li>— <code>result_of_t</code>,</li>
<li>— <code>return_temporary_buffer</code>,</li>
<li>— <code>set_unexpected</code>,</li>
<li><ins>— <code>u8path</code>,</ins></li>
<li>— <code>unary_function</code>,</li>
<li>— <code>unary_negate</code>,</li>
<li>— <code>uncaught_exception</code>,</li>
<li>— <code>unexpected</code>, and</li>
<li>— <code>unexpected_handler</code>.</li>
</ol></li>
</ol>

<h4><del>D.23 Deprecated filesystem path factory functions [depr.fs.path.factory]</del></h4>
<ol>
<pre>
<del>template&lt;class Source&gt;</del>
  <del>path u8path(const Source&amp; source);</del>
<del>template&lt;class InputIterator&gt;</del>
  <del>path u8path(InputIterator first, InputIterator last);</del>
</pre>
<li><del>
<i>Requires:</i> The <code>source</code> and <code>[first, last)</code>
sequences are UTF-8 encoded. The value type of <code>Source</code> and
<code>InputIterator</code> is <code>char</code> or <code>char8_t</code>.
<code>Source</code> meets the requirements specified in 29.11.7.3.
</del></li>
<li><del>
<i>Returns:</i></del>
<ol>
<li><del>
&mdash; If <code>value_type</code> is <code>char</code> and the current native
narrow encoding (29.11.7.2.2) is UTF-8, return <code>path(source)</code> or
<code>path(first, last)</code>; otherwise,
</del></li>
<li><del>
&mdash; if <code>value_type</code> is <code>wchar_t</code> and the native wide
encoding is UTF-16, or if <code>value_type</code> is <code>char16_t</code> or
<code>char32_t</code>, convert <code>source</code> or <code>[first, last)</code>
to a temporary, <code>tmp</code>, of type <code>string_type</code> and return
<code>path(tmp)</code>; otherwise, </del></li>
<li><del>
— convert <code>source</code> or <code>[first, last)</code> to a temporary,
<code>tmp</code>, of type <code>u32string</code> and return <code>path(tmp)</code>.
</del></li>
</ol>
<li><del>
<i>Remarks:</i> Argument format conversion (29.11.7.2.1) applies to the
arguments for these functions. How Unicode encoding conversions are performed
is unspecified.
</del></li>
<li>
<del>[<i>Example:</i> A string is to be read from a database that is encoded in
UTF-8, and used to create a directory using the native encoding for
filenames:</del>
<blockquote><pre>
<del>namespace fs = std::filesystem;</del>
<del>std::string utf8_string = read_utf8_data();</del>
<del>fs::create_directory(fs::u8path(utf8_string));</del>
</pre></blockquote>
<del>For POSIX-based operating systems with the native narrow encoding set to
UTF-8, no encoding or type conversion occurs.</del>
<p><del>
For POSIX-based operating systems with the native narrow encoding not set to
UTF-8, a conversion to UTF-32 occurs, followed by a conversion to the current
native narrow encoding. Some Unicode characters may have no native character
set representation.
</del></p>
<del>For Windows-based operating systems a conversion from UTF-8 to UTF-16
occurs. <i>&mdash;end example</i>] [<i>Note:</i> The example above is
representative of a historical use of <code>filesystem::u8path</code>.  Passing
a <code>std::u8string</code> to <code>path</code>’s constructor is preferred
for an indication of UTF-8 encoding more consistent with <code>path</code>’s
handling of other encodings.  <i>&mdash;end note</i>]</del>
</li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
Discussion was broadly in favor of removal from the C++23 specification, and
relying on library vendors to maintain source compatibility as long as needed.
However, LEWGI explicitly requested to confer with SG16 in case that study
group is aware of any reason to hold back on removal, before proceeding with
the recommendation.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Check with SG16 for any concerns; otherwise remove this feature from C++23
</blockquote>


<!-- =========================== SECTION  BREAK =========================== -->


<h3 id="3.24">Deprecated atomic operations [depr.atomics]</h3>

<blockquote class="note">
<b>First deprecated:</b>
C++20
</blockquote>

<p>
The original API to initialize atomic variables from C++11 was deprecated
for C++20 when the <code>atomic</code> template was given a default constructor to
do the right thing.  See
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0883r2">P0883R2</a>
for details.
</p>
<p>
The legacy API continues to function, but is more cumbersome than necessary.
There appears to be no compelling case that the API is a risk through misuse.
Therefore, given it was so recently deprecated, the strong recommendation is to
retain this feature in Annex D for C++23, giving the community time to catch
up, and consider removal again for C++26.
</p>
<p>
While it does no active harm, there is always a cost to maintaining text in the
standard.  This is similarly reflected in the C standard, that initially
deprecated the <code>ATOMIC_VAR_INT</code> macro (marked it as obsolescent) in
C17, and is actively looking to remove it from the C2X standard, per the paper 
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2390.pdf">WG14:N2390</a>.
It seems likely that the next C standard will ship in the timeframe of C++23,
and will no longer define this macro.  Note that C provides this macro in the
<code>&lt;stdatomic.h&gt;</code> header, which is deliberately excluded from
the set of C headers defined for use by the C++ standard.  For the C++
standard, the application of zombie names means that even if we remove this
clause from Annex D in C++23, standard library vendors are likely to continue
shipping to meet customer demand for some time to come.  So the weak
recommendation is to add the names to the zombie clause, and remove immediately
from C++23.
</p>

<p>
Additionally, the <code>volatile</code> qualified member functions of the
<code>atomic</code> class template were deprecated for C++20 by paper
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a>.
Both the strong and weak recommendations are to leave this feature alone until
the interaction with the non-deprecated non-member functions in the
<code>&lt;atomic&gt;</code> header that take pointer-to-volatile-qualified type.
Possible directions would be to deprecate those non-member functions too, or to
undeprecate the volatile-qualified member functions.
</p>


<blockquote class="recommend">
<b>Strong recommendation:</b>
Take no action.  Reconsider for C++26.
</blockquote>

<blockquote class="note">
No change to draft.
</blockquote>


<blockquote class="recommend">
<b>Weak recommendation:</b>
Remove deprecated atomic initialization feature from C++23
</blockquote>

<blockquote class="draft_wording">
<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li><ins>— <code>ATOMIC_FLAG_INIT</code>,</ins></li>
<li><ins>— <code>atomic_init</code>,</ins></li>
<li><ins>— <code>ATOMIC_VAR_INIT</code>,</ins></li>
<li>— <code>auto_ptr</code>,</li>
<li>— <code>auto_ptr_ref</code>,</li>
<li>— <code>binary_function</code>,</li>
<li>— <code>binary_negate</code>,</li>
<li>— <code>bind1st</code>,</li>
<li>— <code>bind2nd</code>,</li>
<li>— <code>binder1st</code>,</li>
<li>— <code>binder2nd</code>,</li>
<li>— <code>const_mem_fun1_ref_t</code>,</li>
<li>— <code>const_mem_fun1_t</code>,</li>
<li>— <code>const_mem_fun_ref_t</code>,</li>
<li>— <code>const_mem_fun_t</code>,</li>
<li>— <code>get_temporary_buffer</code>,</li>
<li>— <code>get_unexpected</code>,</li>
<li>— <code>gets</code>,</li>
<li>— <code>is_literal_type</code>,</li>
<li>— <code>is_literal_type_v</code>,</li>
<li>— <code>mem_fun1_ref_t</code>,</li>
<li>— <code>mem_fun1_t</code>,</li>
<li>— <code>mem_fun_ref_t</code>,</li>
<li>— <code>mem_fun_ref</code>,</li>
<li>— <code>mem_fun_t</code>,</li>
<li>— <code>mem_fun</code>,</li>
<li>— <code>not1</code>,</li>
<li>— <code>not2</code>,</li>
<li>— <code>pointer_to_binary_function</code>,</li>
<li>— <code>pointer_to_unary_function</code>,</li>
<li>— <code>ptr_fun</code>,</li>
<li>— <code>random_shuffle</code>,</li>
<li>— <code>raw_storage_iterator</code>,</li>
<li>— <code>result_of</code>,</li>
<li>— <code>result_of_t</code>,</li>
<li>— <code>return_temporary_buffer</code>,</li>
<li>— <code>set_unexpected</code>,</li>
<li>— <code>unary_function</code>,</li>
<li>— <code>unary_negate</code>,</li>
<li>— <code>uncaught_exception</code>,</li>
<li>— <code>unexpected</code>, and</li>
<li>— <code>unexpected_handler</code>.</li>
</ol></li>
</ol>

<h4>D.24 Deprecated atomic initialization [depr.atomics]</h4>
<ol>
<li><del>
The header <code>&lt;atomics&gt;</code> (31.2) has the following additions.
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class T&gt;</del>
    <del>void atomic_init(volatile atomic&lt;T&gt;*, typename atomic&lt;T&gt;::value_type) noexcept;</del>
<del>template&lt;class T&gt;</del>
    <del>void atomic_init(atomic&lt;T&gt;*, typename atomic&lt;T&gt;::value_type) noexcept;</del>

<del>#define ATOMIC_VAR_INIT(value) <i>see below</i></del>

<del>#define ATOMIC_FLAG_INIT <i>see below</i></del>
<del>}</del>
</pre></blockquote>
</ol>

<h4>D.24.1 Volatile access [depr.atomics.volatile]</h4>
<p>
If an atomic specialization has one of the following overloads, then that
overload participates in overload resolution even if
<code>atomic&lt;T&gt;::is_always_lock_free</code> is <code>false</code>:
</p>
<blockquote><pre>
void store(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
T operator=(T desired) volatile noexcept;
T load(memory_order order = memory_order::seq_cst) const volatile noexcept;
operator T() const volatile noexcept;
T exchange(T desired, memory_order order = memory_order::seq_cst) volatile noexcept;
bool compare_exchange_weak(T&amp; expected, T desired,
                           memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_strong(T&amp; expected, T desired,
                             memory_order success, memory_order failure) volatile noexcept;
bool compare_exchange_weak(T&amp; expected, T desired,
                           memory_order order = memory_order::seq_cst) volatile noexcept;
bool compare_exchange_strong(T&amp; expected, T desired,
                             memory_order order = memory_order::seq_cst) volatile noexcept;
T fetch_<i>key</i>(T operand, memory_order order = memory_order::seq_cst) volatile noexcept;
T operator op=(T operand) volatile noexcept;
T* fetch_<i>key</i>(ptrdiff_t operand, memory_order order = memory_order::seq_cst) volatile noexcept;
</pre></blockquote>


<h4><del>D.24.2 Non-member functions [depr.atomics.nonmembers]</del></h4>
<pre><del>template&lt;class T&gt;</del>
  <del>void atomic_init(volatile atomic&lt;T&gt;* object, typename atomic&lt;T&gt;::value_type desired) noexcept;</del>
<del>template&lt;class T&gt;</del>
  <del>void atomic_init(atomic&lt;T&gt;* object, typename atomic&lt;T&gt;::value_type desired) noexcept;</del></pre>
<ol>
<li><del>
<i>Effects:</i> Equivalent to: <code>atomic_store_explicit(object, desired, memory_order::relaxed);</code>
</del></li>
</ol>

<h4><del>D.24.3 Operations on atomic types [depr.atomics.types.operations]</del></h4>
<pre><del>#define ATOMIC_VAR_INIT(value) <i>see below</i></del></pre>
<ol>
<li><del>
The macro expands to a token sequence suitable for constant initialization of
an atomic variable of static storage duration of a type that is
initialization-compatible with <code>value</code>. [<i>Note:</i> This operation
may need to initialize locks. <i>&mdash;end note</i>] Concurrent access to the
variable being initialized, even via an atomic operation, constitutes a data
race. [<i>Example:</i>
<blockquote><pre>
<del>atomic&lt;int&gt; v = ATOMIC_VAR_INIT(5);</del>
</pre></blockquote>
<i>&mdash;end example</i>]
</del></li>
</ol>

<h4><del>D.24.4 Flag type and operations [depr.atomics.flag]</del></h4>
<pre><del>#define ATOMIC_FLAG_INIT see below</del></pre>
<ol>
<li><del>
<i>Remarks:</i> The macro <code>ATOMIC_FLAG_INIT</code> is defined in such a
way that it can be used to initialize an object of type
<code>atomic_flag</code> to the clear state. The macro can be used in the form:
<blockquote><pre>
<del>atomic_flag guard = ATOMIC_FLAG_INIT;</del>
</pre></blockquote>
It is unspecified whether the macro can be used in other initialization
contexts. For a complete static-duration object, that initialization shall be
static.
</del></li>
</ol>
</blockquote>

<blockquote class="note">
Draft compatibility note for Annex C.
</blockquote>


<h4>Initial Review: telecon 2020/07/13</h4>
<p>
This topic was immediately deferred to SG1 for initial review, before coming
back to this group.
</p>


<blockquote class="review">
<b>LEWGI Review:</b>
Defer to SG1
</blockquote>

<!-- =========================== SECTION  BREAK =========================== -->


<h2 id="4.0">Other Directions</h2>
<p>
While practicing good housekeeping and clearing out Annex D for each release
may be the preferred option, there are other approaches that may be taken.
</p>

<h4>Do Nothing</h4>
<p>
One approach, epitomized in the Java language, is that deprecated features are
discouraged for future use, but guaranteed to remain available forever, and
just accumulate.
</p>

<p>
This approach is rejected by this paper for a number of reasons.  First, C++
has been relatively successful in actually removing its deprecated features in
the past, a tradition we would like to continue.  It also undercuts the
available-forever rationale, as it is not a guarantee we have given before.
</p>

<p>
A second concern is that we do not want to pay a cost to maintain deprecated
components forever - restricting growth of the language for compatibility with
deprecated features, or having to review the whole of Annex D and upgrade
components for every new language release, in order to keep up with subtle
shifts in the core language.
</p>

<h4>Undeprecate</h4>
<p>
If something is deprecated, but later (re)discovered to have value, then it
could be revitalized and restored to the main standard.  For example, this is
exactly what happened to static function declarations when the unnamed
namespace was given internal linkage - it is merely the classical way to say
the same thing, and often clearer to write.
</p>

<p>
This may be a consideration for long-term deprecated features that don't appear
to be going anywhere, such as the <code>strstream</code> facility, or the C
headers.  It may be appropriate to find them a home in the regular standard,
and this is called out in the specific reviews of each facility above.
</p>


<!-- =========================== SECTION  BREAK =========================== -->


<h2 id="5.0">Integrated Proposed Wording</h2>

<p>
This section integrates the proposed wording of the above recommendations as
the various working groups approve them for review by the Core and Library
Working Groups.  It will apply the wording for mandating Annex D if the
recommendation is to retain a facility.
</p>

<p>
Collected summary of recommendations:
</p>
<table>
  <tr>
    <td><b>Subclause</b></td>
    <td><b>Feature</b></td>
    <td><b>Adopted Recommendation</b></td>
    <td>Action</td>
  </tr>

  <tr>
    <td>D.1</td>
    <td>Arithmetic conversion on enumerations</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.2</td>
    <td>Implicit capture of <code>*this</code> by reference</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.3</td>
    <td>Comma operator in subscript expressions</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.4</td>
    <td>Array comparisons</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.5</td>
    <td>Deprecated use of <code>volatile</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.6</td>
    <td>Reclare <code>constexpr</code> members</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.7</td>
    <td>Non-local use of TU-local entities</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.8</td>
    <td>Implicit special members</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.9</td>
    <td>C <code>&lt;*.h&gt;</code> headers</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.10</td>
    <td><i>Requires:</i> clauses</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.11</td>
    <td><code>relops</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.12</td>
    <td><code>char *</code> streams</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.13</td>
    <td>Deprecated type traits</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.14</td>
    <td>volatile <code>tuple</code> traits</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.15</td>
    <td>volatile <code>variant</code> traits</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.16</td>
    <td><code>std::iterator</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.17</td>
    <td><code>move_iterator::operator-&gt;</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.18</td>
    <td>C API to use <code>shared_ptr</code> atomically</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.19</td>
    <td><code>basic_string::reserve()</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.20</td>
    <td><code>&lt;codecvt&gt;</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.21</td>
    <td><code>wstring_convert</code> et al.</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.22</td>
    <td>Deprecated locale category facets</td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.23</td>
    <td><code>filesystem::u8path</code></td>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td>D.24</td>
    <td>atomic operations</td>
    <td></td>
    <td></td>
  </tr>
 </table>

<p>
Full wording follows:
</p>

<blockquote class="note">
Wording will accumulate (L)EWG recommendations when approved.
</blockquote>

<blockquote class="proposed_wording">
<h4>2 Normative references [intro.refs]</h4>
<ol>
<li>
The following documents are referred to in the text in such a way that some or
all of their content constitutes requirements of this document. For dated
references, only the edition cited applies. For undated references, the latest
edition of the referenced document (including any amendments) applies.
  <ol>
  <li>
&mdash; Ecma International, ECMAScript Language Specification, Standard Ecma-262, third edition, 1999.
  </li>
  <li>
&mdash; ISO/IEC 2382 (all parts), Information technology — Vocabulary
  </li>
  <li>
&mdash; ISO 8601:2004, Data elements and interchange formats — Information interchange — Representation of dates and times
  </li>
  <li>
&mdash; ISO/IEC 9899:2018, Programming languages — C
  </li>
  <li>
&mdash; ISO/IEC 9945:2003, Information Technology — Portable Operating System Interface (POSIX)
  </li>
  <li>
&mdash; ISO/IEC 10646, Information technology — Universal Coded Character Set (UCS)
  </li>
  <li><del>
&mdash; ISO/IEC 10646-1:1993, Information technology — Universal Multiple-Octet Coded Character Set (UCS) — Part 1: Architecture and Basic Multilingual Plane
  </del></li>
  <li>
&mdash; ISO/IEC/IEEE 60559:2011, Information technology — Microprocessor Systems — Floating-Point arithmetic
  </li>
  <li>
&mdash; ISO 80000-2:2009, Quantities and units — Part 2: Mathematical signs and symbols to be used in the natural sciences and technology
  </li>
  </ol>
</li>
<li>
The library described in Clause 7 of ISO/IEC 9899:2018 is hereinafter called
the C standard library.<sup>1</sup>
</li>
<li>
The operating system interface described in ISO/IEC 9945:2003 is hereinafter
called POSIX.
</li>
<li>
The ECMAScript Language Specification described in Standard Ecma-262 is hereinafter called ECMA-262.
</li>
<li><del>
[Note: References to ISO/IEC 10646-1:1993 are used only to support deprecated features (D.19). — end note ]
</del></li>
</ol>


<h4>7.4 Usual arithmetic conversions [expr.arith.conv]</h4>
<ol>
<li>
Many binary operators that expect operands of arithmetic or enumeration type
cause conversions and yield result types in a similar way. The purpose is to
yield a common type, which is also the type of the result. This pattern is
called the <i>usual arithmetic conversions</i>, which are defined as follows:
  <ol>
  <li>
&mdash; If either operand is of scoped enumeration type (9.7.1), no conversions
are performed; if the other operand does not have the same type, the expression
is ill-formed.
  </li>
  <li><ins>
&mdash; Otherwise, if either operand is of unscoped enumeration type (9.7.1)
and the other operand is of a floating-point type, the expression is
ill-formed.
  </ins></li>
  <li>
&mdash; <ins>Otherwise,</ins> if either operand is of type <code>long
double</code>, the other shall be converted to <code>long double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>double</code>, the other shall be
converted to <code>double</code>.
  </li>
  <li>
&mdash; Otherwise, if either operand is <code>float</code>, the other shall be
converted to <code>float</code>.
  </li>
  <li>
&mdash; Otherwise, the integral promotions (7.3.6) shall be performed on both
operands.<sup>56</sup> Then the following rules shall be applied to the
promoted operands:
    <ol>
    <li>
&mdash; If both operands have the same type, no further conversion is needed.
    </li>
    <li>
&mdash; Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer conversion
rank shall be converted to the type of the operand with greater rank.
    </li>
    <li>
&mdash; Otherwise, if the operand that has unsigned integer type has rank
greater than or equal to the rank of the type of the other operand, the operand
with signed integer type shall be converted to the type of the operand with
unsigned integer type.
    </li>
    <li>
&mdash; Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned integer
type, the operand with unsigned integer type shall be converted to the type of
the operand with signed integer type.
    </li>
    <li>
&mdash; Otherwise, both operands shall be converted to the unsigned integer
type corresponding to the type of the operand with signed integer type.
    </li>
    </ol>
  </li>
  </ol>
</li>
<li>
If <del>one</del><ins>either</ins> operand is of <ins>unscoped</ins>
enumeration type and the other operand is of a different enumeration type
<del>or a floating-point type</del>, this behavior is deprecated (D.1).
</li>
</ol>


<h4>7.6.1.1 Subscripting [expr.sub]</h4>
<ol start="2">
<li><del>[<i>Note:</i></del>
A comma expression (7.6.20) appearing as the <i>expr-or-braced-init-list</i> of
a subscripting expression is <ins>ill-formed.</ins><del>deprecated; see
D.3. <i>&mdash;end note</i>]</del>
</li>
</ol>


<h4>7.6.9 Relational operators [expr.rel]</h4>
<ol>
<li>
The relational operators group left-to-right. [<i>Example:</i>
<code>a&lt;b&lt;c</code> means <code>(a&lt;b)&lt;c</code> and not
<code>(a&lt;b)&amp;&amp;(b&lt;c)</code>. <i>&mdash; end example</i>]
<blockquote><pre><i>
relational-expression :
    compare-expression
    relational-expression &lt; compare-expression
    relational-expression &gt; compare-expression
    relational-expression &lt;= compare-expression
    relational-expression &gt;= compare-expression
</i></pre></blockquote>
The lvalue-to-rvalue (7.3.1)<del>, array-to-pointer (7.3.2),</del> and
function-to-pointer(7.3.3) standard conversions are performed on the operands.
<ins>
If at least one of the operands is a pointer, array-to-pointer conversions
(7.3.2) are performed.
</ins>
<del>
The comparison is deprecated if both operands were of array type prior to these
conversions (D.4).
</del>
</li>
<li>
The converted operands shall have arithmetic, enumeration, or pointer type.
The operators <code>&lt;</code> (less than), <code>&gt;</code> (greater than),
<code>&lt;=</code> (less than or equal to), and <code>&gt;=</code> (greater than or
equal to) all yield <code>false</code> or <code>true</code>. The type of the result is
<code>bool</code>.
</li>
<li>
The usual arithmetic conversions (7.4) are performed on operands of arithmetic
or enumeration type. If both operands are pointers, pointer conversions
(7.3.11) and qualification conversions (7.3.5) are performed to bring them to
their composite pointer type (7.2.2). After conversions, the operands shall
have the same type.
</li>
<li>
The result of comparing unequal pointers to objects ...
</li>
</ol>


<h4>7.6.10 Equality operators [expr.eq]</h4>
<blockquote><pre><i>
equality-expression :
    relational-expression
    equality-expression == relational-expression
    equality-expression != relational-expression
</i></pre></blockquote>

<ol>
<li>
The <code>==</code> (equal to) and the <code>!=</code> (not equal to) operators group
left-to-right. The lvalue-to-rvalue (7.3.1)<del>, array-to-pointer
(7.3.2),</del> and function-to-pointer (7.3.3) standard conversions are
performed on the operands.
<del>
The comparison is deprecated if both operands
were of array type prior to these conversions (D.4).
</del>
</li>
<li>
If at least one of the operands is a pointer, <ins>array-to-pointer
conversions (7.3.2),</ins> pointer conversions (7.3.11), function
pointer conversions (7.3.13), and qualification conversions (7.3.5)
are performed on both operands to bring them to their composite
pointer type (7.2.2).
<del>
Comparing pointers is defined as follows:
</del>
</li>
<li>
The converted operands shall have arithmetic, enumeration, pointer,
or pointer-to-member type, or type <code>std::nullptr_t</code>. The
operators <code>==</code> and <code>!=</code> both yield <code>true</code> or
<code>false</code>, i.e., a result of type <code>bool</code>.  In each case
below, the operands shall have the same type after the specified
conversions have been applied.
</li>
<li>
<ins>
Comparing pointers is defined as follows:
</ins>
  <ol>
  <li>
  &mdash; If one pointer represents the address of a complete object,
  and another pointer represents the address one past the last element
  of a different complete object,<sup>79</sup> the result of the comparison is
  unspecified.
</li>
<li>
  &mdash; Otherwise, if the pointers are both null, both point to the
  same function, or both represent the same address (6.8.2), they
  compare equal.
</li>
<li>
  &mdash; Otherwise, the pointers compare unequal.
</li>
  </ol>
</li>
<li>
If at least one of the operands is a pointer to member, ...
</li>
</ol>


<h4>7.6.20 Comma operator [expr.comma]</h4>
<ol start="3">
<li>
[<i>Note:</i> A comma expression (7.6.20) appearing as the
<i>expr-or-braced-init-list</i> of a subscripting expression is <ins>ill-formed</ins><del>deprecated; see
D.3</del>. <i>&mdash;end note</i>]
</li>
</ol>


<h4>16.5.4.3.1 Zombie names [zombie.names]</h4>
<ol>
<li>
In namespace <code>std</code>, the following names are reserved for previous
standardization:
<ol>
<li>&mdash; <code>auto_ptr</code>,</li>
<li>&mdash; <code>auto_ptr_ref</code>,</li>
<li>&mdash; <code>binary_function</code>,</li>
<li>&mdash; <code>binary_negate</code>,</li>
<li>&mdash; <code>bind1st</code>,</li>
<li>&mdash; <code>bind2nd</code>,</li>
<li>&mdash; <code>binder1st</code>,</li>
<li>&mdash; <code>binder2nd</code>,</li>
<li><ins>&mdash; <code>codecvt_mode</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf16</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf8</code>,</ins></li>
<li><ins>&mdash; <code>codecvt_utf8_utf16</code>,</ins></li>
<li>&mdash; <code>const_mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun1_t</code>,</li>
<li>&mdash; <code>const_mem_fun_ref_t</code>,</li>
<li>&mdash; <code>const_mem_fun_t</code>,</li>
<li><ins>&mdash; <code>consume_header</code>,</ins></li>
<li><ins>&mdash; <code>generate_header</code>,</ins></li>
<li>&mdash; <code>get_temporary_buffer</code>,</li>
<li>&mdash; <code>get_unexpected</code>,</li>
<li>&mdash; <code>gets</code>,</li>
<li>&mdash; <code>is_literal_type</code>,</li>
<li>&mdash; <code>is_literal_type_v</code>,</li>
<li><ins>&mdash; <code>is_pod</code>,</ins></li>
<li><ins>&mdash; <code>is_pod_v</code>,</ins></li>
<li><ins>&mdash; <code>iterator</code>,</ins></li>
<li><ins>&mdash; <code>little_endian</code>,</ins></li>
<li>&mdash; <code>mem_fun1_ref_t</code>,</li>
<li>&mdash; <code>mem_fun1_t</code>,</li>
<li>&mdash; <code>mem_fun_ref_t</code>,</li>
<li>&mdash; <code>mem_fun_ref</code>,</li>
<li>&mdash; <code>mem_fun_t</code>,</li>
<li>&mdash; <code>mem_fun</code>,</li>
<li>&mdash; <code>not1</code>,</li>
<li>&mdash; <code>not2</code>,</li>
<li>&mdash; <code>pointer_to_binary_function</code>,</li>
<li>&mdash; <code>pointer_to_unary_function</code>,</li>
<li>&mdash; <code>ptr_fun</code>,</li>
<li>&mdash; <code>random_shuffle</code>,</li>
<li>&mdash; <code>raw_storage_iterator</code>,</li>
<li><ins>&mdash; <code>rel_ops</code>,</ins></li>
<li>&mdash; <code>result_of</code>,</li>
<li>&mdash; <code>result_of_t</code>,</li>
<li>&mdash; <code>return_temporary_buffer</code>,</li>
<li>&mdash; <code>set_unexpected</code>,</li>
<li>&mdash; <code>unary_function</code>,</li>
<li>&mdash; <code>unary_negate</code>,</li>
<li>&mdash; <code>uncaught_exception</code>,</li>
<li>&mdash; <code>unexpected</code>, and</li>
<li>&mdash; <code>unexpected_handler</code>.</li>
</ol>
</li>
<li>
The following names are reserved as member types for previous standardization,
and may not be used as a name for object-like macros in portable code:
  <ol>
  <li>&mdash; <code>argument_type</code>,</li>
  <li>&mdash; <code>first_argument_type</code>,</li>
  <li>&mdash; <code>io_state</code>,</li>
  <li>&mdash; <code>open_mode</code>,</li>
  <li>&mdash; <code>second_argument_type</code>, and</li>
  <li>&mdash; <code>seek_dir</code>.</li>
  </ol>
</li>
<li>
The name <code>stossc</code> is reserved as a member function for previous
standardization, and may not be used as a name for function-like macros in
portable code.
</li>
<li>
The header names
<code>&lt;ccomplex&gt;</code>,
<code>&lt;ciso646&gt;</code>,
<ins><code>&lt;codecvt&gt;</code>,</ins>
<code>&lt;cstdalign&gt;</code>,
<code>&lt;cstdbool&gt;</code>, and
<code>&lt;ctgmath&gt;</code> are reserved for previous
standardization.
</li>
</ol>


<h4><ins>C.1 C++ and ISO C++ 2020</ins></h4>
<ol>
<li><ins>
This subclause lists the differences between C++ and ISO C++ 2020 (ISO/IEC
14882:2020, Programming Languages &mdash; C++), by the chapters of this
document.
</ins></li>
</ol>

<h4><ins>C.1.X Clause 7: Expressions [diff.cpp20.expr]</ins></h4>
<p><ins>
<b>Affected subclause:</b> 7.4</ins>
<i>Note for editors: [expr.arith.conv]</i>
</p>

<p><ins>
<b>Change:</b> Unscoped enumerations do not implicitly promote to integral type
in expressions with floating point types.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 involving both an unscoped
enumeration and a floating point value will be rejected as ill-formed in this
International Standard.  Either argument could be explicitly conerted with a
cast, or the enumeration could be explicitly promoted to an integer with unary
operator +, for no change of meaning since C++ 2020.  [<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>enum multipliers { gigaseconds = 1'000'000 };</ins>
<ins>double century_ish = 3.14 *  gigaseconds;  <i>// ill-formed; previously well-formed</i></ins>
<ins>double century_est = 3.14 * +gigaseconds;  <i>// OK</i></ins>
</pre></blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<p><ins>
<b>Affected subclause:</b> 7.6.1.1</ins>
<i>Note for editors: [expr.sub]</i>
</p>

<p><ins>
<b>Change:</b> Cannot parse unparenthesized comma expressions as subscript
expressions.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was surprising for users familiar with other
languages.  It was removed to allow a future extension to support overloading
the subscript operator for multiple arguments.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 program using a comma
expression as the argument to a subscript expression will be rejected as
ill-formed in this International Standard.  The intended comma expression can
be enclosed in parentheses for no change of meaning since C++ 2020.
[<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>void f(int *a, int b, int c) {</ins>
   <ins>a[b,c];            <i>// ill-formed; previously well-formed</i></ins>
   <ins>a[(b,c)];          <i>// OK</i></ins>
<ins>}</ins>
</pre></blockquote>
<blockquote class="note">
Add an example of a DSEL
</blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<p><ins>
<b>Affected subclause:</b> 7.6.9 and 7.6.10</ins>
<i>Note for editors: [expr.rel] and [expr.eq]</i>
</p>

<p><ins>
<b>Change:</b> Cannot compare two objects of array type.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was confusing, as it did not compare the
contents of the two arrays, but compare their addresses.  Depending on context,
this would either report whether the two arrays were the same object, or have
an unspecified result.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> A valid C++ 2020 program directly comparing
two array objects will be rejected as ill-formed in this International
Standard.
[<i>Example:</i>
</ins></p>
<blockquote><pre>
<ins>int arr1[5];</ins>
<ins>int arr2[5];</ins>
<ins>bool same = arr1 ==  arr2;       <i>// ill-formed; previously well-formed</i></ins>
<ins>bool idem = arr1 == +arr2;       <i>// compare addresses, unspecified result</i></ins>
</pre></blockquote>
<p><ins>
<i>&mdash;end example</i>]
</ins></p>


<h4><ins>C.1.14 Annex D: compatibility features [diff.cpp17.depr]</ins></h4>
<p><ins>
<b>Change:</b> Remove namespace <code>std::rel_ops</code>.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove type trait <code>is_pod</code>.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove <code>volatile</code> specializations of
<code>variant</code> traits.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove <code>std::iterator</code>.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove <code>move_iterator::operator-&gt;</code>.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove <code>basic_string::reserve()</code> with no arguments.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>


<p><ins>
<b>Change:</b> Remove <code>&lt;codecvt&gt;</code> header.
</ins></p>

<p><ins>
<b>Rationale:</b>
<blockquote class="note">
Provide rationale
</blockquote>
</ins></p>

<p><ins>
<b>Effect on original feature:</b>
<blockquote class="note">
Provide examples of code that might break
</blockquote>
</ins></p>




<h4>C.5.3 Clause 7: expressions [diff.expr]</h4>
<p><ins>
<b>Affected subclause:</b> 7.4</ins>
<i>Note for editors: [expr.arith.conv]</i>
</p>

<p><ins>
<b>Change:</b> Enumerations cannot be used in expressions with floating point
types.
</ins></p>

<p><ins>
<b>Rationale:</b> ...
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of semantically well-defined feature.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Could be automated. Violations will be
diagnosed by the C++ translator. The fix is to add a cast, or explicitly
promote the <code>enum</code> object to an integer with unary operator
<code>+</code>. For example:
</ins></p>
<blockquote><pre>
</pre></blockquote>

<p><ins>
<b>How widely used:</b> Common.
</ins></p>


<p><ins>
<b>Affected subclause:</b> 7.6.1.1
</ins><i>Note for editors: [expr.sub]</i><ins>
</ins></p>

<p><ins>
<b>Change:</b> Cannot parse unparenthesized comma expressions as subscript
expressions.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was surprising for users familiar with other
languages.  It was removed to allow a future extension to support overloading
the subscript operator for multiple arguments.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of semantically well-defined feature.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Could be automated. Violations will be
diagnosed by the C++ translator. The fix is to add parentheses. For example:
</ins></p>
<blockquote><pre>
<ins>void f(int *a, int b, int c) {</ins>
   <ins>a[b,c];            <i>// ill-formed; previously well-formed</i></ins>
   <ins>a[(b,c)];          <i>// OK</i></ins>
<ins>}</ins>
</pre></blockquote>

<p><ins>
<b>How widely used:</b> Rare.
</ins></p>


<p><ins>
<b>Affected subclause:</b> 7.6.9 and 7.6.10</ins>
<i>Note for editors: [expr.rel] and [expr.eq]</i>
</p>

<p><ins>
<b>Change:</b> Cannot compare two objects of array type.
</ins></p>

<p><ins>
<b>Rationale:</b> The old behavior was confusing, as it did not compare the
contents of the two arrays, but compare their addresses.  Depending on context,
this would either report whether the two arrays were the same object, or have
an unspecified result.
</ins></p>

<p><ins>
<b>Effect on original feature:</b> Deletion of feature with unspecified behavior.
</ins></p>

<p><ins>
<b>Difficulty of converting:</b> Violations will be diagnosed by the C++
translator.
</ins></p>

<p><ins>
<b>How widely used:</b> Rare. In the cases where the result is well defined,
it is reporting whether both arguments are the same object, using the same
name.
</ins></p>


<h4>D.1 Arithmetic conversion on enumerations [depr.arith.conv.enum]</h4>
<ol>
<li>
The ability to apply the usual arithmetic conversions (7.4) on operands where
one is of <ins>unscoped</ins> enumeration type and the other is of a different
enumeration type <del>or a floating-point type</del> is deprecated. [Note:
Three-way comparisons (7.6.8) between such operands are ill-formed.
<i>&mdash;end note</i>]
[<i>Example:</i>
<blockquote><pre>
enum E1 { e };
enum E2 { f };
<del>bool b = e &lt;= 3.7;                // deprecated</del>
int k = f - e;                    // deprecated
auto cmp = e &lt;=> f;               // error
</pre></blockquote>
<i>&mdash;end example</i>]
</li>
</ol>


<h4><del>D.3 Comma operator in subscript expressions [depr.comma.subscript]</del></h4>
<ol>
<li>
<del>A comma expression (7.6.20) appearing as the <i>expr-or-braced-init-list</i>
of a subscripting expression (7.6.1.1) is deprecated. [<i>Note:</i> A
parenthesized comma expression is not deprecated. <i>&mdash;end note</i>]
[<i>Example:</i></del>
<blockquote><pre>
<del>void f(int *a, int b, int c) {</del>
      <del>a[b,c];                     // deprecated</del>
      <del>a[(b,c)];                   // OK</del>
<del>}</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>


<h4><del>D.4 Array comparisons [depr.array.comp]</del></h4>
<ol>
<li>
<del>Equality and relational comparisons (7.6.10, 7.6.9) between two operands
of array type are deprecated. [<i>Note:</i> Three-way comparisons (7.6.8)
between such operands are ill-formed. <i>&mdash;end note</i>]
[<i>Example:</i></del>
<blockquote><pre>
<del>int arr1[5];</del>
<del>int arr2[5];</del>
<del>bool same = arr1 == arr2;       // deprecated, same as &amp;arr1[0] == &amp;arr2[0],</del>
                                <del>// does not compare array contents</del>
<del>auto cmp = arr1 &lt;=&gt; arr2;       // error</del>
</pre></blockquote>
<del><i>&mdash;end example</i>]</del>
</li>
</ol>


<h4><del>D.11 Relational operators [depr.relops] </del></h4>
<ol>
<li><del>
The header <code>&lt;utility&gt;</code> (20.2.1) has the following additions:
</del></li>

<blockquote><pre>
<del>>namespace std::rel_ops {</del>
  <del>template&lt;class T&gt; bool operator!=(const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&gt; (const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&lt;=(const T&amp;, const T&amp;);</del>
  <del>template&lt;class T&gt; bool operator&gt;=(const T&amp;, const T&amp;);</del>
<del>>}</del>
</pre></blockquote>
<li><del>
To avoid redundant definitions of <code>operator!=</code> out of
<code>operator==</code> and operators <code>&gt;</code>, <code>&lt;=</code>, and
<code>&gt;=</code> out of <code>operator&lt;</code>, the library provides the
following:
</del></li>

<pre><del>template&lt;class T&gt; bool operator!=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17EqualityComparable</i> (Table 23).
</del></li>
<li><del>
<i>Returns:</i> <code>!(x == y)</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&gt;(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>y &lt; x</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&lt;=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>!(y &lt; x)</code>.
</del></li>

<pre><del>template&lt;class T&gt; bool operator&gt;=(const T&amp; x, const T&amp; y);</del></pre>
<li><del>
<i>Requires:</i> Type <code>T</code> is <i>Cpp17LessThanComparable</i> (Table 24).
</del></li>
<li><del>
<i>Returns:</i> <code>!(x &lt; y)</code>.
</del></li>
</ol>


<h4><del>D.13 Deprecated Type Traits [depr.meta.type]</del></h4>
<ol>
<li><del>
The header <code>&lt;type_traits&gt;</code> (20.15.2) has the following additions:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class T&gt; struct is_pod;</del>
  <del>template&lt;class T&gt; inline constexpr bool is_pod_v = is_pod&lt;T&gt;::value;</del>
<del>}</del>
</pre></blockquote>

<li><del>
The behavior of a program that adds specializations for any of the templates
defined in this subclause is undefined, unless explicitly permitted by the
specification of the corresponding template.
</del></li>

<pre><del>template&lt;class T&gt; struct is_pod;</del></pre>
<li><del>
<i>Requires:</i>
<code>remove_all_extents_t&lt;T&gt;</code> shall be a complete type or <i>cv</i> <code>void</code>.
</del></li>

<li><del>
<code>is_pod&lt;T&gt;</code> is a <i>Cpp17UnaryTypeTrait</i> (20.15.1) with a
base characteristic of <code>true_type</code> if <code>T</code> is a POD type,
and <code>false_type</code> otherwise. A POD class is a class that is both a
trivial class and a standard-layout class, and has no non-static data members
of type non-POD class (or array thereof). A POD type is a scalar type, a POD
class, an array of such a type, or a cv-qualified version of one of these
types.
</del></li>

<li><del>
[<i>Note:</i> It is unspecified whether a closure type (7.5.5.1) is a POD type.
<i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.15 Variant [depr.variant]</del></h4>
<ol>
<li><del>
The header <code>&lt;variant&gt;</code> (20.7.2) has the following additions:
</del>
<pre>
<del>namespace std {</del>
  <del>template&lt;class T&gt; struct variant_size&lt;volatile T&gt;;</del>
  <del>template&lt;class T&gt; struct variant_size&lt;const volatile T&gt;;</del>
  <del>template&lt;size_t I, class T&gt; struct variant_alternative&lt;I, volatile T&gt;;</del>
  <del>template&lt;size_t I, class T&gt; struct variant_alternative&lt;I, const volatile T&gt;;</del>
<del>}</del>
</pre>
</li>
<pre>
<del>template&lt;class T&gt; class variant_size&lt;volatile T&gt;;</del>
<del>template&lt;class T&gt; class variant_size&lt;const volatile T&gt;;</del>
</pre>
<li><del>
Let <code>VS</code> denote <code>variant_size&lt;T&gt;</code> of the cv-unqualified type
<code>T</code>. Then specializations of each of the two templates meet the
<i>Cpp17UnaryTypeTrait</i> requirements with a base characteristic of
<code>integral_constant&lt;size_t, VS::value&gt;</code>.
</del></li>
<pre>
<del>template&lt;size_t I, class T&gt; class variant_alternative&lt;I, volatile T&gt;;</del>
<del>template&lt;size_t I, class T&gt; class variant_alternative&lt;I, const volatile T&gt;;</del>
</pre>
<li><del>
Let <code>VA</code> denote <code>variant_alternative&lt;I, T&gt;</code> of the cv-unqualified type <code>T</code>.
Then specializations of each of the two templates meet the
<i>Cpp17TransformationTrait</i> requirements with a member typedef type that names the
following type:
  <ol>
  <li><del>
&mdash; for the first specialization, <code>add_volatile_t&lt;VA::type&gt;</code>, and
  </del></li>
  <li><del>
&mdash; for the second specialization, <code>add_cv_t&lt;VA::type&gt;</code>.
  </del></li>
  </ol>
</del></li>
</ol>


<h4><del>D.16 Deprecated iterator primitives [depr.iterator.primitives]</del></h4>
<h4><del>D.16.1 Basic iterator [depr.iterator.basic]</del></h4>
<ol>
<li><del>
The header <code>&lt;iterator&gt;</code> (23.2) has the following addition:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class Category, class T, class Distance = ptrdiff_t,</del>
    <del>class Pointer = T*, class Reference = T&amp;&gt;</del>
  <del>struct iterator {</del>
    <del>using iterator_category = Category;</del>
    <del>using value_type        = T;</del>
    <del>using difference_type   = Distance;</del>
    <del>using pointer           = Pointer;</del>
    <del>using reference         = Reference;</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<li><del>
The <code>iterator</code> template may be used as a base class to ease the
definition of required types for new iterators.
</del></li>

<li><del>
[ <i>Note:</i> If the new iterator type is a class template, then these
aliases will not be visible from within the iterator class's template
definition, but only to callers of that class <i>&mdash; end note</i>]
</del></li>

<li><del>
[ <i>Example:</i> If a C++ program wants to define a bidirectional iterator for
some data structure containing <code>double</code> and such that it works on a
large memory model of the implementation, it can do so with:
<pre>
<del>class MyIterator :</del>
  <del>public iterator&lt;bidirectional_iterator_tag, double, long, T*, T&amp;&gt; {</del>
  <del><i>// code implementing ++, etc.</i></del>
<del>};</del>
</pre>
&mdash; <i>end example</i> ]
</del></li>
</ol>


<h4><del>D.17 Deprecated move_iterator access [depr.move.iter.elem]</del></h4>
<ol>
<li>
<del>
The following member is declared in addition to those members specified in 23.5.3.5:
</del>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class Iterator&gt;</del>
    <del>class move_iterator {</del>
    <del>public:</del>
      <del>constexpr pointer operator-&gt;() const;</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>
</li>

<pre><del>constexpr pointer operator-&gt;() const;</del></pre>
<li><del>
<i>Returns:</i> <code>current</code>.
</del></li>
</ol>


<h4><del>D.19 Deprecated basic_string capacity [depr.string.capacity]</del></h4>
<ol>
<li><del>
 The following member is declared in addition to those members specified in 21.3.2.4:
</del></li>
<blockquote><pre>
<del>namespace std {</del>
  <del>template&lt;class charT, class traits = char_traits&lt;charT&gt;,</del>
                <del>class Allocator = allocator&lt;charT&gt;&gt;</del>
   <del>class basic_string {</del>
   <del>public:</del>
     <del>void reserve();</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<pre><del>void reserve();</del></pre>
<li><del>
<i>Effects:</i> After this call, <code>capacity()</code> has an unspecified value greater
than or equal to <code>size()</code>. [<i>Note:</i> This is a non-binding shrink to fit
request. <i>&mdash;end note</i>]
</del></li>
</ol>


<h4><del>D.20 Deprecated Standard code conversion facets [depr.locale.stdcvt]</del></h4>
<ol>
<li><del>
The header <code>&lt;codecvt&gt;</code> provides code conversion facets for various
character encodings.
</del></li>
</ol>
<h4><del>D.20.1 Header <code>&lt;codecvt&gt;</code> synopsis [depr.codecvt.syn]</del></h4>
<blockquote><pre>
<del>namespace std {</del>
  <del>enum codecvt_mode {</del>
    <del>consume_header = 4,</del>
    <del>generate_header = 2,</del>
    <del>little_endian = 1</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf8</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf8(size_t refs = 0);</del>
    <del>~codecvt_utf8();</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf16</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf16(size_t refs = 0);</del>
    <del>~codecvt_utf16();</del>
  <del>};</del>

  <del>template&lt;class Elem, unsigned long Maxcode = 0x10ffff,</del>
    <del>codecvt_mode Mode = (codecvt_mode)0&gt;</del>
  <del>class codecvt_utf8_utf16</del>
    <del>: public codecvt&lt;Elem, char, mbstate_t&gt; {</del>
  <del>public:</del>
    <del>explicit codecvt_utf8_utf16(size_t refs = 0);</del>
    <del>~codecvt_utf8_utf16();</del>
  <del>};</del>
<del>}</del>
</pre></blockquote>

<h4><del>D.20.2 Requirements [depr.locale.stdcvt.req]</del></h4>
<ol>
<li><del>
For each of the three code conversion facets <code>codecvt_utf8</code>,
<code>codecvt_utf16</code>, and <code>codecvt_utf8_utf16</code>:
  <ol>
<li><del>
&mdash; <code>Elem</code> is the wide-character type, such as <code>wchar_t</code>,
<code>char16_t</code>, or <code>char32_t</code>.
</del></li>
<li><del>
&mdash; <code>Maxcode</code> is the largest wide-character code that the facet will
read or write without reporting a conversion error.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; consume_header)</code>, the facet shall consume an
initial header sequence, if present, when reading a multibyte sequence to
determine the endianness of the subsequent multibyte sequence to be read.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; generate_header)</code>, the facet shall generate an
initial header sequence when writing a multibyte sequence to advertise the
endianness of the subsequent multibyte sequence to be written.
</del></li>
<li><del>
&mdash; If <code>(Mode &amp; little_endian)</code>, the facet shall generate a
multibyte sequence in little-endian order, as opposed to the default big-endian
order.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf8</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-8 multibyte sequences and UCS2 or
UTF-32 (depending on the size of <code>Elem</code>) within the program.
</del></li>
<li><del>
&mdash; Endianness shall not affect how multibyte sequences are read or written.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written as either a text or a binary file.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf16</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-16 multibyte sequences and UCS2 or
UTF-32 (depending on the size of <code>Elem</code>) within the program.
</del></li>
<li><del>
&mdash; Multibyte sequences shall be read or written according to the
<code>Mode</code> flag, as set out above.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written only as a binary file.
Attempting to write to a text file produces undefined behavior.
</del></li>
  </ol>
</del></li>

<li><del>
For the facet <code>codecvt_utf8_utf16</code>:
  <ol>
<li><del>
&mdash; The facet shall convert between UTF-8 multibyte sequences and UTF-16
(one or two 16-bit codes) within the program.
</del></li>
<li><del>
&mdash; Endianness shall not affect how multibyte sequences are read or written.
</del></li>
<li><del>
&mdash; The multibyte sequences may be written as either a text or a binary file.
</del></li>
  </ol>
</del></li>

<li><del>
The encoding forms UTF-8, UTF-16, and UTF-32 are specified in ISO/IEC 10646.
The encoding form UCS-2 is specified in ISO/IEC 10646-1:1993.
</del></li>
</ol>


<h4>D.21.1 Class template wstring_convert [depr.conversions.string]</h4>
<ol>
<li>
Class template <code>wstring_convert</code> performs conversions between a wide
string and a byte string.  It lets you specify a code conversion facet (like
class template <code>codecvt</code>) to perform the conversions, without
affecting any streams or locales.  [ <i>Example:</i>  If you <del>want to use
the code conversion facet <code>codecvt_utf8</code></del> <ins>have a code
conversion facet named <code>codecvt_utf8</code> that you want to use</ins> to
output to <code>cout</code> a UTF-8 multibyte sequence corresponding to a wide
string, but you don’t want to alter the locale for <code>cout</code>, you can
write something like:
<blockquote><pre>
<ins>std::</ins>wstring_convert&lt;<del>std::</del>codecvt_utf8&lt;wchar_t&gt;&gt; myconv;
std::string mbstring = myconv.to_bytes(L"Hello\n");
std::cout &lt;&lt; mbstring;
</pre></blockquote>
&mdash; <i>end example</i> ]
</li>
</ol>

</blockquote>


<h2 id="6.0">Acknowledgements</h2>
<p>
Special thanks to Hal Finkel for allowing a late update to track the latest IS
wording in the mailing.  Thanks to Stephan T. Lavavej for the early review, and
catching too many spelling and grammar errors!
</p>

<p>
Thanks to everyone who worked on flagging these facilities for deprecation,
let's take the next step!
</p>


<h2 id="7.0">References</h2>
<ul>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2007">N2007</a>
PROPOSED LIBRARY ADDITIONS FOR CODE CONVERSION,
P.J. Plauger
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2238">N2238</a>
Minimal Unicode support for the standard library,
Matthew Austern
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2401">N2401</a>
Code Conversion Facets for the Standard C++ Library,
P.J. Plauger
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3201">N3201</a>
Moving right along,
Bjarne Stroustrup
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3203">N3203</a>
Tightening the conditions for generating implicit moves,
Jens Maurer
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4086">N4086</a>
Removing trigraphs??!,
Richard Smith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/n4861">N4861</a>
C++ Standard Working Draft (at inception of C++23),
Richard Smith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0174r0">P0174R2</a>
Deprecating Vestigial Library Parts in C++17,
Alisdair Meredith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0270r3">P0270R3</a>
Removing C dependencies from signal handler wording,
Hans-J. Boehm
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0386r2">P0386R2</a>
Inline Variables,
Hal Finkel and Richard Smith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0448r2">P0448R2</a>
A strstream replacement using <code>span&lt;charT&gt;</code> as buffer,
Peter Sommerlad
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6">P0482R6</a>
<code>char8_t</code>: A type for UTF-8 characters and strings,
Tom Honermann
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0">P0618R0</a>
Deprecating <code>&lt;codecvt&gt;</code>,
Alisdair Meredith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0619r4">P0619R4</a>
Reviewing Deprecated Facilities of C++17 for C++20,
Alisdair Meredith, Stephan T. Lavavej, Tomasz Kamiński
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0718r2">P0718R2</a>
Revising <code>atomic_shared_ptr</code> for C++20,
Alisdair Meredith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0767r1">P0767R1</a>
Deprecate POD,
Jens Maurer
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0768r1">P0768R1</a>
Library Support for the Spaceship (Comparison) Operator,
Walter E. Brown
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0788r3">pP788R3</a>
Standard Library Specification in a Concepts and Contracts World,
Walter E. Brown
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0806r2">P0806R2</a>
Deprecate implicit capture of <code>this</code> via <code>[=]</code>,
Thomas Köppe
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0883r2">P0883R2</a>
Fixing Atomic Initialization,
Nicolai Josuttis
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0896r4">P0896R4</a>
The One Ranges Proposal,
Eric Niebler, Casey Carter, Christopher Di Bella
  </li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0966r1">P0966R1</a>
<code>string::reserve</code> Should Not Shrink,
Mark Zeren, Andrew Luo
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1152r4">P1152R4</a>
Deprecating <code>volatile</code>,
JF Bastien
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1161r3">P1161R3</a>
Deprecate uses of the comma operator in subscripting expressions,
Corentin Jabot
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1120r0">P1120R0</a>
Consistency improvements for &lt;=&gt; and other comparison operators,
Richard Smith
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1252r2">P1252R2</a>
Ranges Design Cleanup,
Casey Carter
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1815r2">P1815R2</a>
Translation-unit-local entities,
S. Davis Herring
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1831r1">P1831R1</a>
Deprecating <code>volatile</code>: library,
JF Bastien
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2128r0">P2128R1</a>
Multidimensional subscript operator,
Mark Hoemmen, DS Hollman, Corentin Jabot, Isabella Muerte, Christian Trott
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2390.pdf">WG14:N2390</a>
Remove <code>ATOMIC_VAR_INIT</code>,
Jens Gustedt
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2458.pdf">WG14:N2457</a>
Revise spelling of keywords v4,
Jens Gustedt
  </li>
  <li>
<a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2458.pdf">WG14:N2458</a>
Make false and true first-class language features v3,
Jens Gustedt
  </li>
</ul>

</body>
</html>
