<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>P2085R0: Consistent defaulted comparisons</title>
  <style>
    code{white-space: pre-wrap;}
    span.smallcaps{font-variant: small-caps;}
    span.underline{text-decoration: underline;}
    div.column{display: inline-block; vertical-align: top; width: 50%;}
    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
    ul.task-list{list-style: none;}
    pre > code.sourceCode { white-space: pre; position: relative; }
    pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
    pre > code.sourceCode > span:empty { height: 1.2em; }
    code.sourceCode > span { color: inherit; text-decoration: inherit; }
    div.sourceCode { margin: 1em 0; }
    pre.sourceCode { margin: 0; }
    @media screen {
    div.sourceCode { overflow: auto; }
    }
    @media print {
    pre > code.sourceCode { white-space: pre-wrap; }
    pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
    }
    pre.numberSource code
      { counter-reset: source-line 0; }
    pre.numberSource code > span
      { position: relative; left: -4em; counter-increment: source-line; }
    pre.numberSource code > span > a:first-child::before
      { content: counter(source-line);
        position: relative; left: -1em; text-align: right; vertical-align: baseline;
        border: none; display: inline-block;
        -webkit-touch-callout: none; -webkit-user-select: none;
        -khtml-user-select: none; -moz-user-select: none;
        -ms-user-select: none; user-select: none;
        padding: 0 4px; width: 4em;
        color: #aaaaaa;
      }
    pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
    div.sourceCode
      {   }
    @media screen {
    pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
    }
    code span.al { color: #ff0000; font-weight: bold; } /* Alert */
    code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
    code span.at { color: #7d9029; } /* Attribute */
    code span.bn { color: #40a070; } /* BaseN */
    code span.bu { } /* BuiltIn */
    code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
    code span.ch { color: #4070a0; } /* Char */
    code span.cn { color: #880000; } /* Constant */
    code span.co { color: #60a0b0; font-style: italic; } /* Comment */
    code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
    code span.do { color: #ba2121; font-style: italic; } /* Documentation */
    code span.dt { color: #902000; } /* DataType */
    code span.dv { color: #40a070; } /* DecVal */
    code span.er { color: #ff0000; font-weight: bold; } /* Error */
    code span.ex { } /* Extension */
    code span.fl { color: #40a070; } /* Float */
    code span.fu { color: #06287e; } /* Function */
    code span.im { } /* Import */
    code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
    code span.kw { color: #007020; font-weight: bold; } /* Keyword */
    code span.op { color: #666666; } /* Operator */
    code span.ot { color: #007020; } /* Other */
    code span.pp { color: #bc7a00; } /* Preprocessor */
    code span.sc { color: #4070a0; } /* SpecialChar */
    code span.ss { color: #bb6688; } /* SpecialString */
    code span.st { color: #4070a0; } /* String */
    code span.va { color: #19177c; } /* Variable */
    code span.vs { color: #4070a0; } /* VerbatimString */
    code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <style type="text/css">
  div.del, section.del { background: #fcd; }
  div.ins, section.ins { background: #bfa; }
  s, .del { background: #ff8888; }
  u, .ins { background: #88ff88; }
  /* from https://stackoverflow.com/a/32456613 */
  div > blockquote, body > blockquote {
      display: list-item;
      list-style-type: "- ";
  }
  pre {
  		margin-left: 1.2em;
  }
  .tony {
    border-collapse: collapse;
  }
  .tony > tbody > tr {
    vertical-align: top;
  }
  tr.hr, tr.hr {
    border-bottom: thin solid #60a0b0;  /* relies on collapse */
  }
  </style>
</head>
<body>
<header id="title-block-header">
<h1 class="title">P2085R0: Consistent defaulted comparisons<!-- -*- c++-md -*- --></h1>
</header>
<p><em>Audience</em>: EWG, CWG<br />
S. Davis Herring &lt;<a href="mailto:herring@lanl.gov" class="email">herring@lanl.gov</a>&gt;<br />
Los Alamos National Laboratory<br />
February 14, 2020</p>
<h1 id="background">Background</h1>
<p>Special member functions may be defaulted in or out of their class:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">class</span> MysteryCopy {</span>
<span id="cb1-2"><a href="#cb1-2"></a>  <span class="dt">int</span> a,b,c,d,e,f,g;</span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="kw">public</span>:</span>
<span id="cb1-4"><a href="#cb1-4"></a>  MysteryCopy()=<span class="cf">default</span>;            <span class="co">// value initialization zeros</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>  MysteryCopy(<span class="at">const</span> MysteryCopy&amp;);  <span class="co">// not trivially copyable</span></span>
<span id="cb1-6"><a href="#cb1-6"></a>};</span>
<span id="cb1-7"><a href="#cb1-7"></a></span>
<span id="cb1-8"><a href="#cb1-8"></a>MysteryCopy::MysteryCopy(<span class="at">const</span> MysteryCopy&amp;)=<span class="cf">default</span>;</span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="co">// still not trivially copyable; equivalent to</span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="co">// MysteryCopy::MysteryCopy(const MysteryCopy &amp;m) /* noexcept(false) */</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="co">//   : a(m.a),b(m.b),c(m.c),d(m.d),e(m.e),f(m.f),g(m.g) {}</span></span></code></pre></div>
<p>The separate definition allows the programmer to control special properties of the function (<code>constexpr</code> and <code>inline</code>) and of the class (various kinds of triviality) without having to write a long definition manually (here, to copy each member). In particular, unless the out-of-class definition is declared <code>inline</code>, it will typically appear in a separate translation unit and will provide ABI stability (as described in [dcl.fct.def.default]/5) and avoid duplicate code generation. It’s even possible to declare the function <code>inline</code>, <code>constexpr</code>, or <code>consteval</code> in the class but provide its defaulted definition (and thus allow its use) only in certain translation units. (By contrast, the exception specification is controllable even in the class via <code>noexcept(false)</code>.)</p>
<p>The situation for comparison functions is less clear. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0515r3.pdf">P0515R3</a> merely requires that a defaulted comparison be “declared in the <em>member-specification</em> of C”, which can be taken to allow <code>=default</code> on a redeclaration of a friend. In fact, that paper goes further and mentions the possibility of access checks for non-member, <em>non-friend</em> defaulted <code>operator&lt;=&gt;</code>. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0732r2.pdf">P0732R2</a> defines strong structural equality in terms of an <code>operator&lt;=&gt;</code> defaulted in the definition of a class, as would be compatible with being able to do so elsewhere. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1185r2.html">P1185R2</a> preserves these wording details when separating <code>==</code> from <code>&lt;=&gt;</code> and does not mention the possibility at all.</p>
<p>There is no record of any Evolution discussion of where to allow <code>=default</code> since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3950.html">N3950</a>, whose revisions <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4114.htm">N4114</a> and <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4126.htm">N4126</a> included “unanimously requested” support for non-members. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0432r0.html">P0432R0</a>, which revived the syntax, retained that support.</p>
<p>However, the recollection of Core (at the January 16 issues-processing teleconference) is that the intent was to require that <code>=default</code> be used only within a class for comparisons, and <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2002r1.html">P2002R1</a> clarifies the rule to say so. Although <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1907r1.html">P1907R1</a> removed the relevant class property of strong structural equality, this restriction does have the effect of making it <em>impossible</em> to default a comparison without making it inline (and possibly constexpr). This seems undesirable from an expressivity standpoint; one of the reasons for introducing default comparisons was to avoid writing error-prone repetitive code manually, but anyone who wants to control the properties of a comparison operator must do so (and potentially reimplement the synthesized three-way comparisons from [class.spaceship]/1). It also seems needlessly inconsistent with the other functions (the special members) that can be defaulted.</p>
<p>There is another reason for comparison functions to not be inline: the linkage concerns in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1498r1.html">P1498R1</a>. Those issues matter little for defaulted special member functions, which principally call member functions of types that already must be available to any translation unit that can call the defaulted function. For that reason and for consistency reasons, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1779r3.html">P1779R3</a> does not affect the implicit <code>inline</code> for functions defaulted in a class. However, it would not be at all unexpected for a defaulted comparison to invoke non-member subobject comparisons with internal linkage (because they are meaningless to clients). Such a comparison would be allowed by <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1815r1.html">P1815R1</a> only if it were made opaque by being defined outside a class.</p>
<h1 id="proposal">Proposal</h1>
<p>To allow defaulted comparisons to be non-inline (to control ABI or code generation), or inline but not constexpr (even if constexpr-compatible), allow their definition to appear outside the class that declares them (possibly as a friend). Retain the restriction that they be <em>declared</em> in the relevant class to avoid encouraging clients to add to a class’s interface (and to avoid questions of access).</p>
<p>Hidden friend comparison operators can be defaulted in an implementation translation unit, or in a <em>private-module-fragment</em>, to avoid being inline while remaining hidden. A member of, or an unbounded set of friends injected by, a class template cannot be so isolated, but clients must be able to generate code for them anyway.</p>
<h2 id="tony-table">Tony table</h2>
<table class="tony">
<tr>
<th>
N4849
</th>
<th>
</th>
<th>
this proposal
</th>
</tr>
<tr class="hr">
<td>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">struct</span> Ints {</span>
<span id="cb2-2"><a href="#cb2-2"></a>  <span class="dt">int</span> i,j,k;</span>
<span id="cb2-3"><a href="#cb2-3"></a>  <span class="co">// since we had to add k recently:</span></span>
<span id="cb2-4"><a href="#cb2-4"></a>  <span class="co">// std::unique_ptr&lt;int[]&gt; rest;</span></span>
<span id="cb2-5"><a href="#cb2-5"></a></span>
<span id="cb2-6"><a href="#cb2-6"></a>  <span class="co">// This can&#39;t be constexpr once we add &#39;rest&#39;, so don&#39;t rely on that now.</span></span>
<span id="cb2-7"><a href="#cb2-7"></a>  <span class="kw">friend</span> <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Ints&amp;,<span class="at">const</span> Ints&amp;);</span>
<span id="cb2-8"><a href="#cb2-8"></a>};</span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="kw">inline</span> <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Ints &amp;a,<span class="at">const</span> Ints &amp;b) {</span>
<span id="cb2-10"><a href="#cb2-10"></a>  <span class="cf">return</span> a.i==b.i &amp;&amp; a.j==b.j;  <span class="co">// oops</span></span>
<span id="cb2-11"><a href="#cb2-11"></a>}</span></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">struct</span> Ints {</span>
<span id="cb3-2"><a href="#cb3-2"></a>  <span class="dt">int</span> i,j,k;</span>
<span id="cb3-3"><a href="#cb3-3"></a>  <span class="co">// since we had to add k recently:</span></span>
<span id="cb3-4"><a href="#cb3-4"></a>  <span class="co">// std::unique_ptr&lt;int[]&gt; rest;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a></span>
<span id="cb3-6"><a href="#cb3-6"></a>  <span class="co">// This can&#39;t be constexpr once we add &#39;rest&#39;, so don&#39;t rely on that now.</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>  <span class="kw">friend</span> <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Ints&amp;,<span class="at">const</span> Ints&amp;);</span>
<span id="cb3-8"><a href="#cb3-8"></a>};</span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="kw">inline</span> <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Ints&amp;,<span class="at">const</span> Ints&amp;)=<span class="cf">default</span>;</span></code></pre></div>
</td>
</tr>
<tr class="hr">
<td>
<p>weak.hpp:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#ifndef WEAK_HPP</span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="pp">#define WEAK_HPP</span></span>
<span id="cb4-3"><a href="#cb4-3"></a></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="pp">#include</span><span class="im">&lt;compare&gt;</span></span>
<span id="cb4-5"><a href="#cb4-5"></a></span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="kw">struct</span> Legacy {</span>
<span id="cb4-7"><a href="#cb4-7"></a>  <span class="co">// ...</span></span>
<span id="cb4-8"><a href="#cb4-8"></a>  <span class="co">// These define a weak order:</span></span>
<span id="cb4-9"><a href="#cb4-9"></a>  <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Legacy&amp;) <span class="at">const</span> {<span class="co">/* lots of code */</span>}</span>
<span id="cb4-10"><a href="#cb4-10"></a>  <span class="dt">bool</span> <span class="kw">operator</span>&lt;(<span class="at">const</span> Legacy&amp;) <span class="at">const</span> {<span class="co">/* lots of code */</span>}</span>
<span id="cb4-11"><a href="#cb4-11"></a>};</span>
<span id="cb4-12"><a href="#cb4-12"></a></span>
<span id="cb4-13"><a href="#cb4-13"></a><span class="kw">struct</span> Spaceship {</span>
<span id="cb4-14"><a href="#cb4-14"></a>  Legacy a,b,c;</span>
<span id="cb4-15"><a href="#cb4-15"></a>  <span class="co">// This is a lot of code; let&#39;s generate it once:</span></span>
<span id="cb4-16"><a href="#cb4-16"></a>  <span class="bu">std::</span>weak_ordering <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Spaceship&amp;) <span class="at">const</span>;</span>
<span id="cb4-17"><a href="#cb4-17"></a>};</span>
<span id="cb4-18"><a href="#cb4-18"></a></span>
<span id="cb4-19"><a href="#cb4-19"></a><span class="pp">#endif</span></span></code></pre></div>
<p>weak.cpp:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="pp">#include</span><span class="im">&quot;weak.hpp&quot;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="bu">std::</span>weak_ordering Spaceship::<span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Spaceship &amp;s) <span class="at">const</span> {</span>
<span id="cb5-4"><a href="#cb5-4"></a>  <span class="cf">if</span>(!(a==s.a))</span>
<span id="cb5-5"><a href="#cb5-5"></a>    <span class="cf">return</span> a&lt;s.a ? <span class="bu">std::</span>weak_ordering<span class="bu">::</span>less : <span class="bu">std::</span>weak_ordering<span class="bu">::</span>greater;</span>
<span id="cb5-6"><a href="#cb5-6"></a>  <span class="cf">if</span>(!(b==s.b))</span>
<span id="cb5-7"><a href="#cb5-7"></a>    <span class="cf">return</span> b&lt;s.b ? <span class="bu">std::</span>weak_ordering<span class="bu">::</span>less : <span class="bu">std::</span>weak_ordering<span class="bu">::</span>greater;</span>
<span id="cb5-8"><a href="#cb5-8"></a>  <span class="cf">if</span>(!(c==s.c))</span>
<span id="cb5-9"><a href="#cb5-9"></a>    <span class="cf">return</span> c&lt;s.c ? <span class="bu">std::</span>weak_ordering<span class="bu">::</span>less : <span class="bu">std::</span>weak_ordering<span class="bu">::</span>greater;</span>
<span id="cb5-10"><a href="#cb5-10"></a>  <span class="cf">return</span> <span class="bu">std::</span>weak_ordering<span class="bu">::</span>equivalent;</span>
<span id="cb5-11"><a href="#cb5-11"></a>}</span></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<p>weak.hpp:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="pp">#ifndef WEAK_HPP</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="pp">#define WEAK_HPP</span></span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></a><span class="pp">#include</span><span class="im">&lt;compare&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5"></a></span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="kw">struct</span> Legacy {</span>
<span id="cb6-7"><a href="#cb6-7"></a>  <span class="co">// ...</span></span>
<span id="cb6-8"><a href="#cb6-8"></a>  <span class="co">// These define a weak order:</span></span>
<span id="cb6-9"><a href="#cb6-9"></a>  <span class="dt">bool</span> <span class="kw">operator</span>==(<span class="at">const</span> Legacy&amp;) <span class="at">const</span> {<span class="co">/* lots of code */</span>}</span>
<span id="cb6-10"><a href="#cb6-10"></a>  <span class="dt">bool</span> <span class="kw">operator</span>&lt;(<span class="at">const</span> Legacy&amp;) <span class="at">const</span> {<span class="co">/* lots of code */</span>}</span>
<span id="cb6-11"><a href="#cb6-11"></a>};</span>
<span id="cb6-12"><a href="#cb6-12"></a></span>
<span id="cb6-13"><a href="#cb6-13"></a><span class="kw">struct</span> Spaceship {</span>
<span id="cb6-14"><a href="#cb6-14"></a>  Legacy a,b,c;</span>
<span id="cb6-15"><a href="#cb6-15"></a>  <span class="co">// This is a lot of code; let&#39;s generate it once:</span></span>
<span id="cb6-16"><a href="#cb6-16"></a>  <span class="bu">std::</span>weak_ordering <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Spaceship&amp;) <span class="at">const</span>;</span>
<span id="cb6-17"><a href="#cb6-17"></a>};</span>
<span id="cb6-18"><a href="#cb6-18"></a></span>
<span id="cb6-19"><a href="#cb6-19"></a><span class="pp">#endif</span></span></code></pre></div>
<p>weak.cpp:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="pp">#include</span><span class="im">&quot;weak.hpp&quot;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="bu">std::</span>weak_ordering Spaceship::<span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Spaceship&amp;) <span class="at">const</span>=<span class="cf">default</span>;</span></code></pre></div>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">export</span> module A;</span>
<span id="cb8-2"><a href="#cb8-2"></a>import&lt;compare&gt;;</span>
<span id="cb8-3"><a href="#cb8-3"></a></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="kw">class</span> Helper {</span>
<span id="cb8-5"><a href="#cb8-5"></a>  <span class="co">// ...</span></span>
<span id="cb8-6"><a href="#cb8-6"></a>};</span>
<span id="cb8-7"><a href="#cb8-7"></a><span class="kw">namespace</span> {  <span class="co">// users shouldn&#39;t call this; it&#39;s surprisingly expensive</span></span>
<span id="cb8-8"><a href="#cb8-8"></a>  <span class="bu">std::</span>partial_ordering <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Helper &amp;a,<span class="at">const</span> Helper &amp;b) {</span>
<span id="cb8-9"><a href="#cb8-9"></a>    <span class="co">// ...</span></span>
<span id="cb8-10"><a href="#cb8-10"></a>  }</span>
<span id="cb8-11"><a href="#cb8-11"></a>}</span>
<span id="cb8-12"><a href="#cb8-12"></a></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="kw">export</span> <span class="kw">class</span> Public {</span>
<span id="cb8-14"><a href="#cb8-14"></a>  <span class="dt">int</span> i;</span>
<span id="cb8-15"><a href="#cb8-15"></a>  Helper h1,h2;</span>
<span id="cb8-16"><a href="#cb8-16"></a><span class="kw">public</span>:</span>
<span id="cb8-17"><a href="#cb8-17"></a>  <span class="co">// ...</span></span>
<span id="cb8-18"><a href="#cb8-18"></a>  <span class="bu">std::</span>partial_ordering <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Public&amp;) <span class="at">const</span>;</span>
<span id="cb8-19"><a href="#cb8-19"></a>};</span>
<span id="cb8-20"><a href="#cb8-20"></a><span class="bu">std::</span>partial_ordering Public::<span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Public &amp;p) <span class="at">const</span> {</span>
<span id="cb8-21"><a href="#cb8-21"></a>  <span class="co">// can&#39;t use return type deduction: this would be std::strong_ordering</span></span>
<span id="cb8-22"><a href="#cb8-22"></a>  <span class="cf">if</span>(<span class="at">const</span> <span class="kw">auto</span> v=i&lt;=&gt;p.i; v!=<span class="dv">0</span>) <span class="cf">return</span> v;</span>
<span id="cb8-23"><a href="#cb8-23"></a>  <span class="cf">if</span>(<span class="at">const</span> <span class="kw">auto</span> v=h1&lt;=&gt;p.h1; v!=<span class="dv">0</span>) <span class="cf">return</span> v;</span>
<span id="cb8-24"><a href="#cb8-24"></a>  <span class="cf">return</span> h2&lt;=&gt;p.h2;</span>
<span id="cb8-25"><a href="#cb8-25"></a>}</span></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">export</span> module A;</span>
<span id="cb9-2"><a href="#cb9-2"></a>import&lt;compare&gt;;</span>
<span id="cb9-3"><a href="#cb9-3"></a></span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="kw">class</span> Helper {</span>
<span id="cb9-5"><a href="#cb9-5"></a>  <span class="co">// ...</span></span>
<span id="cb9-6"><a href="#cb9-6"></a>};</span>
<span id="cb9-7"><a href="#cb9-7"></a><span class="kw">namespace</span> {  <span class="co">// users shouldn&#39;t call this; it&#39;s surprisingly expensive</span></span>
<span id="cb9-8"><a href="#cb9-8"></a>  <span class="bu">std::</span>partial_ordering <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Helper &amp;a,<span class="at">const</span> Helper &amp;b) {</span>
<span id="cb9-9"><a href="#cb9-9"></a>    <span class="co">// ...</span></span>
<span id="cb9-10"><a href="#cb9-10"></a>  }</span>
<span id="cb9-11"><a href="#cb9-11"></a>}</span>
<span id="cb9-12"><a href="#cb9-12"></a></span>
<span id="cb9-13"><a href="#cb9-13"></a><span class="kw">export</span> <span class="kw">class</span> Public {</span>
<span id="cb9-14"><a href="#cb9-14"></a>  <span class="dt">int</span> i;</span>
<span id="cb9-15"><a href="#cb9-15"></a>  Helper h1,h2;</span>
<span id="cb9-16"><a href="#cb9-16"></a><span class="kw">public</span>:</span>
<span id="cb9-17"><a href="#cb9-17"></a>  <span class="co">// ...</span></span>
<span id="cb9-18"><a href="#cb9-18"></a>  <span class="kw">auto</span> <span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Public&amp;) <span class="at">const</span>;</span>
<span id="cb9-19"><a href="#cb9-19"></a>};</span>
<span id="cb9-20"><a href="#cb9-20"></a><span class="kw">auto</span> Public::<span class="kw">operator</span>&lt;=&gt;(<span class="at">const</span> Public&amp;) <span class="at">const</span>=<span class="cf">default</span>;</span></code></pre></div>
</td>
</tr>
</table>
<h1 id="wording">Wording</h1>
<h2 id="relative-to-n4849">Relative to N4849</h2>
<h3 id="class.compare.default">[class.compare.default]</h3>
<p>Change paragraph 1:</p>
<blockquote>
<p>A defaulted comparison operator function ([over.binary]) for some class <code>C</code> shall be a non-template function<s> declared in the <em>member-specification</em> of <code>C</code></s> that is</p>
<ol type="1">
<li>a non-static const member of <code>C</code> having one parameter of type <code>const C&amp;</code>, or</li>
<li>a friend of <code>C</code> having either two parameters of type <code>const C&amp;</code> or two parameters of type <code>C</code>.</li>
</ol>
</blockquote>
<p>Change paragraph 3:</p>
<blockquote>
<p>If the class definition does not explicitly declare an <code>==</code> operator function, but declares a <s>defaulted </s>three-way comparison operator function<u> as defaulted</u>, an <code>==</code> operator function is declared implicitly with the same access as the three-way comparison operator function. The implicitly-declared <code>==</code> operator for a class <code>X</code> is an inline member and is defined as defaulted in the definition of <code>X</code>. If the three-way comparison operator function is declared as a non-static const member, the implicitly-declared <code>==</code> operator function is a member of the form</p>
<p>[…]</p>
</blockquote>
<h2 id="relative-to-n4849-as-modified-by-p2002r1">Relative to N4849 as modified by P2002R1</h2>
<h3 id="class.compare.default-1">[class.compare.default]</h3>
<p>Change paragraph 1:</p>
<blockquote>
<p>A defaulted comparison operator function ([over.binary]) for some class <code>C</code> shall be a non-template function<s> defined in the <em>member-specification</em> of <code>C</code></s> that is</p>
<ol type="1">
<li>a non-static const non-volatile member of <code>C</code> having one parameter of type <code>const C&amp;</code> and either no <em>ref-qualifier</em> or the <em>ref-qualifier</em> <code>&amp;</code>, or</li>
<li>a friend of <code>C</code> having either two parameters of type <code>const C&amp;</code> or two parameters of type <code>C</code>.</li>
</ol>
<p>A <s>defaulted </s>comparison operator function for class <code>C</code> that is <u>defaulted on its first declaration and is </u>not defined as deleted is <em>implicitly defined</em> when it is odr-used or needed for constant evaluation. Name lookups in the defaulted definition<u> of a comparison operator function</u> are performed from a context equivalent to <s>the</s><u>its</u> <em>function-body</em><s> of the defaulted <code>operator@</code> function</s>. <s>A defaulted</s><u>A definition of a</u> comparison operator <s>function shall be</s><u>as</u> defaulted <s>on its</s><u>that appears in a class shall be the</u> first declaration<u> of that function</u>.</p>
</blockquote>
<p>Change paragraph 3 (editorially, for clarity):</p>
<blockquote>
<p>If the <em>member-specification</em> does not explicitly declare any member or friend named <code>operator==</code>, an <code>==</code> operator function is declared implicitly for each <s>defaulted </s>three-way comparison operator function defined<u> as defaulted</u> in the <em>member-specification</em>, with the same access and <em>function-definition</em> and in the same class scope as the three-way comparison operator function, except that the return type is replaced with <code>bool</code> and the <em>declarator-id</em> is replaced with <code>operator==</code>. [<em>Note</em>: […] — <em>end note</em>] [<em>Example</em>:</p>
<p>[…]</p>
<p>— <em>end example</em>] [<em>Note</em>: […] — <em>end note</em>]</p>
</blockquote>
<h1 id="acknowledgments">Acknowledgments</h1>
<p>Thanks to Richard Smith for helping identify use cases.</p>
</body>
</html>
