<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-03-20" />
  <title>Comparisons for reference_wrapper</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
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #e6ffed;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Comparisons for <code class="sourceCode cpp">reference_wrapper</code></h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2944R3</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-03-20</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#ambiguity-issues"><span class="toc-section-number">2.1</span> Ambiguity Issues<span></span></a></li>
<li><a href="#non-boolean-comparisons"><span class="toc-section-number">2.2</span> Non-boolean comparisons<span></span></a></li>
<li><a href="#constraints-vs-mandates"><span class="toc-section-number">2.3</span> Constraints vs Mandates<span></span></a></li>
</ul></li>
<li><a href="#proposal"><span class="toc-section-number">3</span> Proposal<span></span></a>
<ul>
<li><a href="#feature-test-macro"><span class="toc-section-number">3.1</span> Feature-test macro<span></span></a></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">4</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P2944R2">[<a href="#ref-P2944R2" role="doc-biblioref">P2944R2</a>]</span>, wording fixes.</p>
<p>Since <span class="citation" data-cites="P2944R1">[<a href="#ref-P2944R1" role="doc-biblioref">P2944R1</a>]</span>, added section on <a href="#ambiguity-issues">ambiguity</a> and updated wording accordingly.</p>
<p>Since <span class="citation" data-cites="P2944R0">[<a href="#ref-P2944R0" role="doc-biblioref">P2944R0</a>]</span>, fixed the wording</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Typically in libraries, wrapper types are comparable when their underlying types are comparable. <code class="sourceCode cpp">tuple<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is equality comparable when <code class="sourceCode cpp">T</code> is. <code class="sourceCode cpp">optional<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is equality comparable when <code class="sourceCode cpp">T</code> is. <code class="sourceCode cpp">variant<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is equality comparable when <code class="sourceCode cpp">T</code> is.</p>
<p>But <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is a peculiar type in this respect. It looks like this:</p>
<blockquote>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">class</span> reference_wrapper <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>  <span class="co">// types</span></span>
<span id="cb1-4"><a href="#cb1-4"></a>  <span class="kw">using</span> type <span class="op">=</span> T;</span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a>  <span class="co">// [refwrap.const], constructors</span></span>
<span id="cb1-7"><a href="#cb1-7"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> U<span class="op">&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8"></a>    <span class="kw">constexpr</span> reference_wrapper<span class="op">(</span>U<span class="op">&amp;&amp;)</span> <span class="kw">noexcept</span><span class="op">(</span><em>see below</em><span class="op">)</span>;</span>
<span id="cb1-9"><a href="#cb1-9"></a>  <span class="kw">constexpr</span> reference_wrapper<span class="op">(</span><span class="kw">const</span> reference_wrapper<span class="op">&amp;</span> x<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb1-10"><a href="#cb1-10"></a></span>
<span id="cb1-11"><a href="#cb1-11"></a>  <span class="co">// [refwrap.assign], assignment</span></span>
<span id="cb1-12"><a href="#cb1-12"></a>  <span class="kw">constexpr</span> reference_wrapper<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> reference_wrapper<span class="op">&amp;</span> x<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb1-13"><a href="#cb1-13"></a></span>
<span id="cb1-14"><a href="#cb1-14"></a>  <span class="co">// [refwrap.access], access</span></span>
<span id="cb1-15"><a href="#cb1-15"></a>  <span class="kw">constexpr</span> <span class="kw">operator</span> T<span class="op">&amp;()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb1-16"><a href="#cb1-16"></a>  <span class="kw">constexpr</span> T<span class="op">&amp;</span> get<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb1-17"><a href="#cb1-17"></a></span>
<span id="cb1-18"><a href="#cb1-18"></a>  <span class="co">// [refwrap.invoke], invocation</span></span>
<span id="cb1-19"><a href="#cb1-19"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> ArgTypes<span class="op">&gt;</span></span>
<span id="cb1-20"><a href="#cb1-20"></a>    <span class="kw">constexpr</span> invoke_result_t<span class="op">&lt;</span>T<span class="op">&amp;</span>, ArgTypes<span class="op">...&gt;</span> <span class="kw">operator</span><span class="op">()(</span>ArgTypes<span class="op">&amp;&amp;...)</span> <span class="kw">const</span></span>
<span id="cb1-21"><a href="#cb1-21"></a>      <span class="kw">noexcept</span><span class="op">(</span>is_nothrow_invocable_v<span class="op">&lt;</span>T<span class="op">&amp;</span>, ArgTypes<span class="op">...&gt;)</span>;</span>
<span id="cb1-22"><a href="#cb1-22"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>When <code class="sourceCode cpp">T</code> is not equality comparable, it is not surprising that <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is not equality comparable. But what about when <code class="sourceCode cpp">T</code> <em>is</em> equality comparable? There are no comparison operators here, but nevertheless the answer is… maybe?</p>
<p>Because <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is implicitly convertible to <code class="sourceCode cpp">T<span class="op">&amp;</span></code> and <code class="sourceCode cpp">T</code> is an associated type of <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, <code class="sourceCode cpp">T</code>’s equality operator (if it exists) might be viable candidate. But it depends on exactly what <code class="sourceCode cpp">T</code> is and how the equality operator is defined. Given a type <code class="sourceCode cpp">T</code> and an object <code class="sourceCode cpp">t</code> such that <code class="sourceCode cpp">t <span class="op">==</span> t</code> is valid, let’s consider the validity of the expressions <code class="sourceCode cpp">ref<span class="op">(</span>t<span class="op">)</span> <span class="op">==</span> ref<span class="op">(</span>t<span class="op">)</span></code> and <code class="sourceCode cpp">ref<span class="op">(</span>t<span class="op">)</span> <span class="op">==</span> t</code> for various possible types <code class="sourceCode cpp">T</code>:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">T</code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">ref<span class="op">(</span>t<span class="op">)</span> <span class="op">==</span> ref<span class="op">(</span>t<span class="op">)</span></code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">ref<span class="op">(</span>t<span class="op">)</span> <span class="op">==</span> t</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>builtins</td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>class or class template with member <code class="sourceCode cpp"><span class="op">==</span></code></td>
<td>❌</td>
<td>✔️ (since C++20)</td>
</tr>
<tr class="odd">
<td>class with non-member or hidden friend <code class="sourceCode cpp"><span class="op">==</span></code></td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>class template with hidden friend <code class="sourceCode cpp"><span class="op">==</span></code></td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>class template with non-member, template <code class="sourceCode cpp"><span class="op">==</span></code></td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">std<span class="op">::</span>string_view</code></td>
<td>❌</td>
<td>✔️</td>
</tr>
</tbody>
</table>
<p>That’s a weird table!</p>
<p>Basically, if <code class="sourceCode cpp">T</code> is equality comparable, then <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is… sometimes… depending on how <code class="sourceCode cpp">T</code>’s comparisons are defined. <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> is equality comparable, but <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span></code> is not. Nor is <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>std<span class="op">::</span>string_view<span class="op">&gt;</span></code> but you can nevertheless compare a <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>std<span class="op">::</span>string_view<span class="op">&gt;</span></code> to a <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>.</p>
<p>So, first and foremost: sense, this table makes none.</p>
<p>Second, there are specific use-cases to want <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> to be normally equality comparable, and those use-cases are the same reason what <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> exists to begin with: deciding when to capture a value by copy or by reference.</p>
<p>Consider wanting to have a convenient shorthand for a predicate to check for equality against a value. This is something that shows up in lots of libraries (e.g. Björn Fahller’s <a href="https://github.com/rollbear/lift/blob/3927d06415f930956341afd5bc223f912042d7e4/include/lift.hpp#L150-L158">lift</a> or Conor Hoekstra’s <a href="https://github.com/codereport/blackbird/blob/623490fbfb4b8ef68bcda723d22b055b27e4d6ed/combinators.hpp#L43">blackbird</a>), and looks something like this:</p>
<blockquote>
<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">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> equals <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> value<span class="op">){</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>  <span class="cf">return</span> <span class="op">[</span>value<span class="op">=</span>FWD<span class="op">(</span>value<span class="op">)](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">){</span> <span class="cf">return</span> value <span class="op">==</span> e; <span class="op">}</span>;</span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>Which allows the nice-looking:</p>
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="cf">if</span> <span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>any_of<span class="op">(</span>v, equals<span class="op">(</span><span class="dv">0</span><span class="op">)))</span> <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2"></a>    <span class="co">// ...</span></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>But this implementation always copies (or moves) the value into the lambda. For larger types, this is wasteful. But we don’t want to either unconditionally capture by reference (which sometimes leads to dangling) or write a parallel hierarchy of reference-capturing function objects (which is lots of code duplication and makes the library just worse).</p>
<p>This is <em>exactly</em> the problem that <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> solves for the standard library: if I want to capture something by reference into <code class="sourceCode cpp">std<span class="op">::</span>bind</code> or <code class="sourceCode cpp">std<span class="op">::</span>thread</code> or anything else, I pass the value as <code class="sourceCode cpp">std<span class="op">::</span>ref<span class="op">(</span>v<span class="op">)</span></code>. Otherwise, I pass <code class="sourceCode cpp">v</code>. We should be able to use the exact same solution here, without having to change the definition of <code class="sourceCode cpp">equals</code>:</p>
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="cf">if</span> <span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>any_of<span class="op">(</span>v, equals<span class="op">(</span>std<span class="op">::</span>ref<span class="op">(</span>target<span class="op">))))</span> <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>    <span class="co">// ...</span></span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>And this works! Just… only for some types, seemingly randomly. The goal of this proposal is for it to just always work.</p>
<h2 data-number="2.1" id="ambiguity-issues"><span class="header-section-number">2.1</span> Ambiguity Issues<a href="#ambiguity-issues" class="self-link"></a></h2>
<p>In the original revision of the paper, the proposal was simply to add this equality operator:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">class</span> reference_wrapper <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, reference_wrapper<span class="op">)</span>;</span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>But this turns out to be insufficient. It’s enough for <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> to become comparable for all cases, but that’s not exactly all we need. Consider:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">auto</span> check<span class="op">(</span><span class="dt">int</span> i, std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2"></a>  <span class="cf">return</span> i <span class="op">==</span> r;</span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This comparison is valid today, per the table earlier: we convert <code class="sourceCode cpp">r</code> to <code class="sourceCode cpp"><span class="dt">int</span></code> through its <code class="sourceCode cpp"><span class="kw">operator</span> <span class="dt">int</span><span class="op">&amp;()</span></code> and use the builtin comparison. But now we’re adding a new candidate, which is also valid: we can convert <code class="sourceCode cpp">i</code> to <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>. These two candidates are ambiguous. The same is true for many other similar comparisons.</p>
<p>In order to ensure that we catch all the interesting cases, we can build up all the comparisons that we want to check. For non-const <code class="sourceCode cpp">T</code>:</p>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="kw">concept</span> ref_equality_comparable <span class="op">=</span> <span class="kw">requires</span> <span class="op">(</span>T a, T <span class="kw">const</span> ca, Ref<span class="op">&lt;</span>T<span class="op">&gt;</span> r, Ref<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&gt;</span> cr<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3"></a>    <span class="co">// the usual T is equality-comparable with itself</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>    a <span class="op">==</span> a;</span>
<span id="cb7-5"><a href="#cb7-5"></a>    a <span class="op">==</span> ca;</span>
<span id="cb7-6"><a href="#cb7-6"></a>    ca <span class="op">==</span> ca;</span>
<span id="cb7-7"><a href="#cb7-7"></a></span>
<span id="cb7-8"><a href="#cb7-8"></a>    <span class="co">// Ref&lt;T&gt; is equality-comparable with itself</span></span>
<span id="cb7-9"><a href="#cb7-9"></a>    r <span class="op">==</span> r;</span>
<span id="cb7-10"><a href="#cb7-10"></a>    r <span class="op">==</span> cr;</span>
<span id="cb7-11"><a href="#cb7-11"></a>    cr <span class="op">==</span> cr;</span>
<span id="cb7-12"><a href="#cb7-12"></a></span>
<span id="cb7-13"><a href="#cb7-13"></a>    <span class="co">// T and Ref&lt;T&gt; are equality-comparable</span></span>
<span id="cb7-14"><a href="#cb7-14"></a>    a <span class="op">==</span> r;</span>
<span id="cb7-15"><a href="#cb7-15"></a>    a <span class="op">==</span> cr;</span>
<span id="cb7-16"><a href="#cb7-16"></a>    ca <span class="op">==</span> r;</span>
<span id="cb7-17"><a href="#cb7-17"></a>    ca <span class="op">==</span> cr;</span>
<span id="cb7-18"><a href="#cb7-18"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>We don’t need to check both directions of comparison anymore, but we do need to check const and non-const comparisons - which means <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">T <span class="kw">const</span></code> for the objects and <code class="sourceCode cpp">Ref<span class="op">&lt;</span>T<span class="op">&gt;</span></code> and <code class="sourceCode cpp">Ref<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&gt;</span></code> for our reference wrapper. We need to be careful to check both because of the case I just showed earlier - <code class="sourceCode cpp"><span class="dt">int</span> <span class="op">==</span> reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> would be ambiguous with the rules laid out in R0 and R1 of this paper, but <code class="sourceCode cpp"><span class="dt">int</span> <span class="kw">const</span> <span class="op">==</span> reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> actually would be fine (because <code class="sourceCode cpp"><span class="dt">int</span> <span class="kw">const</span><span class="op">&amp;</span></code> is not convertible to <code class="sourceCode cpp">reference_wrapper<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>, so we only have one viable candidate).</p>
<p>That concept fails for every type with the R0/R1 proposal. To disambigugate, we need to add an extra comparison to handle the <code class="sourceCode cpp">T <span class="op">==</span> Ref<span class="op">&lt;</span>T<span class="op">&gt;</span></code> case:`</p>
<blockquote>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">class</span> reference_wrapper <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, reference_wrapper<span class="op">)</span>;</span>
<span id="cb8-3"><a href="#cb8-3"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, T <span class="kw">const</span><span class="op">&amp;)</span>;</span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>That gets us a lot closer, but it still isn’t sufficient. Actually only one single expression now fails: the <code class="sourceCode cpp">r <span class="op">==</span> cr</code> (<code class="sourceCode cpp">Ref<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">==</span> Ref<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&gt;</span></code>) check, which fails for all <code class="sourceCode cpp">T</code>. The previous ambiguity is annoying, but this one particularly so since we just need a dedicated comparison operator <em>just</em> for this case. Which we can add:</p>
<blockquote>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">class</span> reference_wrapper <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, reference_wrapper<span class="op">)</span>;</span>
<span id="cb9-3"><a href="#cb9-3"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, T <span class="kw">const</span><span class="op">&amp;)</span>;</span>
<span id="cb9-4"><a href="#cb9-4"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>reference_wrapper, reference_wrapper<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&gt;)</span>; <span class="co">// only for non-const T</span></span>
<span id="cb9-5"><a href="#cb9-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>And that, now, passes <a href="https://godbolt.org/z/eTs71o49o">all the tests</a>.</p>
<h2 data-number="2.2" id="non-boolean-comparisons"><span class="header-section-number">2.2</span> Non-boolean comparisons<a href="#non-boolean-comparisons" class="self-link"></a></h2>
<p>Another question that came up with in the LEWG telecon was how this proposal interacts with non-boolean comparison operators. For instance:</p>
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="dt">void</span> f<span class="op">(</span>std<span class="op">::</span>valarray<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2"></a>  <span class="co">// this is a valid expression today, whose type is not bool, but rather</span></span>
<span id="cb10-3"><a href="#cb10-3"></a>  <span class="co">// something convertible to std::valarray&lt;bool&gt;</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>  v <span class="op">==</span> v;</span>
<span id="cb10-5"><a href="#cb10-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Now, <code class="sourceCode cpp">std<span class="op">::</span>valarray<span class="op">&lt;</span>T<span class="op">&gt;</span></code>’s comparison operators are specified as non-member function templates, so any comparison using <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>std<span class="op">::</span>valarray<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span></code> doesn’t work today. But let’s make our own version of this type that’s more friendly (or hostile, depending on your perspective) to this paper and consider:</p>
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a><span class="kw">struct</span> ValArray <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3"></a>  <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">==(</span>ValArray <span class="kw">const</span><span class="op">&amp;</span>, ValArray <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">-&gt;</span> ValArray<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4"></a>    <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb11-5"><a href="#cb11-5"></a>  <span class="op">}</span></span>
<span id="cb11-6"><a href="#cb11-6"></a><span class="op">}</span>;</span>
<span id="cb11-7"><a href="#cb11-7"></a></span>
<span id="cb11-8"><a href="#cb11-8"></a><span class="dt">void</span> f<span class="op">(</span>ValArray<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-9"><a href="#cb11-9"></a>  <span class="co">// this is valid and has type ValArray&lt;bool&gt;</span></span>
<span id="cb11-10"><a href="#cb11-10"></a>  v <span class="op">==</span> v;</span>
<span id="cb11-11"><a href="#cb11-11"></a></span>
<span id="cb11-12"><a href="#cb11-12"></a>  <span class="co">// this is also valid today and has the same type</span></span>
<span id="cb11-13"><a href="#cb11-13"></a>  std<span class="op">::</span>ref<span class="op">(</span>v<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>ref<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb11-14"><a href="#cb11-14"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Now, does anybody write such code? Who knows. If we <a href="#constraints-vs-mandates">constrain</a> the comparisons of <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> (and also the other standard library types), then this code will continue to work fine anyway - since the comparisons would be constrained away by types like <code class="sourceCode cpp">ValArray<span class="op">&lt;</span>T<span class="op">&gt;</span></code> not satisfying <code class="sourceCode cpp">equality_comparable</code>. This paper would not be adding any new candidates to the candidate set, so no behavior changes.</p>
<p>But, as always, there is an edge case.</p>
<ol type="1">
<li>there is a type <code class="sourceCode cpp">T</code>, whose comparisons return a type like <code class="sourceCode cpp"><span class="dt">int</span></code></li>
<li>and those comparisons are written in such a way that comparison <code class="sourceCode cpp">T</code> to <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> works (see table above)</li>
<li>and users are relying on such comparisons to actually return <code class="sourceCode cpp"><span class="dt">int</span></code></li>
</ol>
<p>Then the comparisons to <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> will instead start returning <code class="sourceCode cpp"><span class="dt">bool</span></code>. That is:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">struct</span> ComparesAsInt <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2"></a>  <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">==(</span>ComparseAsInt, ComparesAsInt<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span>;</span>
<span id="cb12-3"><a href="#cb12-3"></a><span class="op">}</span>;</span>
<span id="cb12-4"><a href="#cb12-4"></a></span>
<span id="cb12-5"><a href="#cb12-5"></a><span class="kw">auto</span> f<span class="op">(</span>std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>ComparesAsInt<span class="op">&gt;</span> a, std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>ComparesAsInt<span class="op">&gt;</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-6"></a>  <span class="co">// today: compiles and returns int</span></span>
<span id="cb12-7"><a href="#cb12-7"></a>  <span class="co">// proposed: compiles and returns bool</span></span>
<span id="cb12-8"><a href="#cb12-8"></a>  <span class="cf">return</span> a <span class="op">==</span> b;</span>
<span id="cb12-9"><a href="#cb12-9"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Here, the added comparison operators would be valid, and wouldn’t constrain away, since <code class="sourceCode cpp">std<span class="op">::</span>equality_comparable</code> is based on <code class="sourceCode cpp"><em>boolean-testable</em></code> which only requires convertibility to <code class="sourceCode cpp"><span class="dt">bool</span></code> (and some other nice behavior), which <code class="sourceCode cpp"><span class="dt">int</span></code> does satisfy. And those added comparison operators would be better matches than the existing ones, so they would win.</p>
<p>This would be the only case where any behavior would change.</p>
<h2 data-number="2.3" id="constraints-vs-mandates"><span class="header-section-number">2.3</span> Constraints vs Mandates<a href="#constraints-vs-mandates" class="self-link"></a></h2>
<p>Surprisingly, the status quo today is that for standard library types <code class="sourceCode cpp">std<span class="op">::</span>pair</code>, <code class="sourceCode cpp">std<span class="op">::</span>tuple</code>, etc., the spaceship operator is constrained (by way of <code class="sourceCode cpp"><em>synth-three-way-result</em><span class="op">&lt;</span>T<span class="op">&gt;</span></code>) but the equality operators and existing relational operators actually are <em>Mandated</em> instead. There does not seem to be a particularly good reason for this. It kind of just happened - the relational comparisons became constrained by way of my <span class="citation" data-cites="P1614R2">[<a href="#ref-P1614R2" role="doc-biblioref">P1614R2</a>]</span>, and the equality ones just weren’t touched. It would make a lot more sense to have all of them constrained, so that <code class="sourceCode cpp">std<span class="op">::</span>equality_comparable<span class="op">&lt;</span>std<span class="op">::</span>tuple<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span></code> wasn’t just <code class="sourceCode cpp"><span class="kw">true</span></code> for all <code class="sourceCode cpp">T</code> (well, except <code class="sourceCode cpp"><span class="dt">void</span></code> and incomplete types).</p>
<p>This paper proposes as a drive-by to also make all the comparison operators <em>Constrained</em> instead of <em>Mandated</em>.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">3</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>Add <code class="sourceCode cpp"><span class="op">==</span></code> and <code class="sourceCode cpp"><span class="op">&lt;=&gt;</span></code> to <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> so that <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is always comparable when <code class="sourceCode cpp">T</code> is, regardless of how <code class="sourceCode cpp">T</code>’s comparisons are defined.</p>
<p>Change <span>22.10.6.1 <a href="https://wg21.link/refwrap.general">[refwrap.general]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1"></a>  template&lt;class T&gt; class reference_wrapper {</span>
<span id="cb13-2"><a href="#cb13-2"></a>  public:</span>
<span id="cb13-3"><a href="#cb13-3"></a>    // types</span>
<span id="cb13-4"><a href="#cb13-4"></a>    using type = T;</span>
<span id="cb13-5"><a href="#cb13-5"></a></span>
<span id="cb13-6"><a href="#cb13-6"></a>    // [refwrap.const], constructors</span>
<span id="cb13-7"><a href="#cb13-7"></a>    template&lt;class U&gt;</span>
<span id="cb13-8"><a href="#cb13-8"></a>      constexpr reference_wrapper(U&amp;&amp;) noexcept(<em>see below</em>);</span>
<span id="cb13-9"><a href="#cb13-9"></a>    constexpr reference_wrapper(const reference_wrapper&amp; x) noexcept;</span>
<span id="cb13-10"><a href="#cb13-10"></a></span>
<span id="cb13-11"><a href="#cb13-11"></a>    // [refwrap.assign], assignment</span>
<span id="cb13-12"><a href="#cb13-12"></a>    constexpr reference_wrapper&amp; operator=(const reference_wrapper&amp; x) noexcept;</span>
<span id="cb13-13"><a href="#cb13-13"></a></span>
<span id="cb13-14"><a href="#cb13-14"></a>    // [refwrap.access], access</span>
<span id="cb13-15"><a href="#cb13-15"></a>    constexpr operator T&amp; () const noexcept;</span>
<span id="cb13-16"><a href="#cb13-16"></a>    constexpr T&amp; get() const noexcept;</span>
<span id="cb13-17"><a href="#cb13-17"></a></span>
<span id="cb13-18"><a href="#cb13-18"></a>    // [refwrap.invoke], invocation</span>
<span id="cb13-19"><a href="#cb13-19"></a>    template&lt;class... ArgTypes&gt;</span>
<span id="cb13-20"><a href="#cb13-20"></a>      constexpr invoke_result_t&lt;T&amp;, ArgTypes...&gt; operator()(ArgTypes&amp;&amp;...) const</span>
<span id="cb13-21"><a href="#cb13-21"></a>        noexcept(is_nothrow_invocable_v&lt;T&amp;, ArgTypes...&gt;);</span>
<span id="cb13-22"><a href="#cb13-22"></a></span>
<span id="cb13-23"><a href="#cb13-23"></a><span class="va">+   // [refwrap.comparisons], comparisons</span></span>
<span id="cb13-24"><a href="#cb13-24"></a><span class="va">+   friend constexpr bool operator==(reference_wrapper, reference_wrapper);</span></span>
<span id="cb13-25"><a href="#cb13-25"></a><span class="va">+   friend constexpr bool operator==(reference_wrapper, const T&amp;);</span></span>
<span id="cb13-26"><a href="#cb13-26"></a><span class="va">+   friend constexpr bool operator==(reference_wrapper, reference_wrapper&lt;const T&gt;);</span></span>
<span id="cb13-27"><a href="#cb13-27"></a></span>
<span id="cb13-28"><a href="#cb13-28"></a><span class="va">+   friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper, reference_wrapper);</span></span>
<span id="cb13-29"><a href="#cb13-29"></a><span class="va">+   friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper, const T&amp;);</span></span>
<span id="cb13-30"><a href="#cb13-30"></a><span class="va">+   friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper, reference_wrapper&lt;const T&gt;);</span></span>
<span id="cb13-31"><a href="#cb13-31"></a>  };</span></code></pre></div>
</div>
<p>…</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">3</a></span> The template parameter <code class="sourceCode cpp">T</code> of <code class="sourceCode cpp">reference_wrapper</code> may be an incomplete type.</p>
<div class="addu">
<p><span class="note"><span>[ <em>Note 1:</em> </span>Using the comparison operators described in subclause [refwrap.comparisons] with <code class="sourceCode cpp">T</code> being an incomplete type can lead to an ill-formed program with no diagnostic required ([temp.point], [temp.constr.atomic])<span> — <em>end note</em> ]</span></span></p>
</div>
</blockquote>
<p>Add a new clause, [refwrap.comparisons], after <span>22.10.6.5 <a href="https://wg21.link/refwrap.invoke">[refwrap.invoke]</a></span>:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb14"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb14-1"><a href="#cb14-1"></a>friend constexpr bool operator==(reference_wrapper x, reference_wrapper y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">1</a></span> <em>Constraints</em>: The expression <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y<span class="op">.</span>get<span class="op">()</span></code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">2</a></span> <em>Returns</em>: <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y<span class="op">.</span>get<span class="op">()</span></code>.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb15-1"><a href="#cb15-1"></a>friend constexpr bool operator==(reference_wrapper x, const T&amp; y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">3</a></span> <em>Constraints</em>: The expression <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">4</a></span> <em>Returns</em>: <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y</code>.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1"></a>friend constexpr bool operator==(reference_wrapper x, reference_wrapper&lt;const T&gt; y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">5</a></span> <em>Constraints</em>: <code class="sourceCode cpp">is_const_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code> and the expression <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y<span class="op">.</span>get<span class="op">()</span></code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">6</a></span> <em>Returns</em>: <code class="sourceCode cpp">x<span class="op">.</span>get<span class="op">()</span> <span class="op">==</span> y<span class="op">.</span>get<span class="op">()</span></code>.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb17-1"><a href="#cb17-1"></a>friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper x, reference_wrapper y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">7</a></span> <em>Returns</em>: <code class="sourceCode cpp"><em>synth-three-way</em><span class="op">(</span>x<span class="op">.</span>get<span class="op">()</span>, y<span class="op">.</span>get<span class="op">())</span></code>.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1"></a>friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper x, const T&amp; y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">8</a></span> <em>Returns</em>: <code class="sourceCode cpp"><em>synth-three-way</em><span class="op">(</span>x<span class="op">.</span>get<span class="op">()</span>, y<span class="op">)</span></code>.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1"></a>friend constexpr <em>synth-three-way-result</em>&lt;T&gt; operator&lt;=&gt;(reference_wrapper x, reference_wrapper&lt;const T&gt; y);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">9</a></span> <em>Constraints</em>: <code class="sourceCode cpp">is_const_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">10</a></span> <em>Returns</em>: <code class="sourceCode cpp"><em>synth-three-way</em><span class="op">(</span>x<span class="op">.</span>get<span class="op">()</span>, y<span class="op">.</span>get<span class="op">())</span></code>.</p>
</div>
</blockquote>
<p>And then additional drive-by changes for existing library types as follows.</p>
<p>In <span>22.3.3 <a href="https://wg21.link/pairs.spec">[pairs.spec]</a></span>/1:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">1</a></span> <span class="rm" style="color: #bf0303"><del><em>Preconditions</em></del></span> <span class="addu"><em>Constraints</em></span>: <span class="addu"><code class="sourceCode cpp">x<span class="op">.</span>first <span class="op">==</span> y<span class="op">.</span>first</code> and <code class="sourceCode cpp">x<span class="op">.</span>second <span class="op">==</span> y<span class="op">.</span>second</code> are valid expressions and each</span> <span class="rm" style="color: #bf0303"><del>Each</del></span> of <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(</span>x<span class="op">.</span>first <span class="op">==</span> y<span class="op">.</span>first<span class="op">)</span></code> and <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(</span>x<span class="op">.</span>second <span class="op">==</span> y<span class="op">.</span>second<span class="op">)</span></code> models <code class="sourceCode cpp"><em>boolean-testable</em></code>.</p>
</blockquote>
<p>In <span>22.4.9 <a href="https://wg21.link/tuple.rel">[tuple.rel]</a></span>/2:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">2</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: For all <code class="sourceCode cpp">i</code>, where <code class="sourceCode cpp"><span class="dv">0</span> <span class="op">&lt;=</span> i <span class="op">&lt;</span> <span class="kw">sizeof</span><span class="op">...(</span>TTypes<span class="op">)</span></code>, <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">==</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>u<span class="op">)</span></code> is a valid expression <span class="addu">and <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span>i<span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">==</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>u<span class="op">))</span></code> models <code class="sourceCode cpp"><em>boolean-testable</em></code></span>. <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">...(</span>TTypes<span class="op">)</span></code> equals <code class="sourceCode cpp">tuple_size_v<span class="op">&lt;</span>UTuple<span class="op">&gt;</span></code>.</p>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">3</a></span> <em>Preconditions</em>: For all <code class="sourceCode default">i</code>, <code class="sourceCode default">decltype(get&lt;i&gt;(t) == get&lt;i&gt;(u))</code> models <code class="sourceCode default"><em>boolean-testable</em></code>.</p>
</div>
</blockquote>
<p>In <span>22.5.6 <a href="https://wg21.link/optional.relops">[optional.relops]</a></span>, change all the <em>Mandates</em> to <em>Constraints</em>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">1</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">==</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">4</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">!=</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">7</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&lt;</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">10</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&gt;</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">13</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&lt;=</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">16</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&gt;=</span> <span class="op">*</span>y</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
</blockquote>
<p>In <span>22.5.8 <a href="https://wg21.link/optional.comp.with.t">[optional.comp.with.t]</a></span>, change all the <em>Mandates</em> to <em>Constraints</em>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">1</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">==</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">3</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">==</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">5</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">!=</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">7</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">!=</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">9</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&lt;</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">11</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">&lt;</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">13</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&gt;</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_28" id="pnum_28">15</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">&gt;</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_29" id="pnum_29">17</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&lt;=</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_30" id="pnum_30">19</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">&lt;=</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_31" id="pnum_31">21</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp"><span class="op">*</span>x <span class="op">&gt;=</span> v</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_32" id="pnum_32">23</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: The expression <code class="sourceCode cpp">v <span class="op">&gt;=</span> <span class="op">*</span>x</code> is well-formed and its result is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
</blockquote>
<p>In <span>22.6.6 <a href="https://wg21.link/variant.relops">[variant.relops]</a></span>, change all the <em>Mandates</em> to <em>Constraints</em>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_33" id="pnum_33">1</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">==</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_34" id="pnum_34">3</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">!=</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_35" id="pnum_35">5</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">&lt;</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_36" id="pnum_36">7</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">&gt;</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_37" id="pnum_37">9</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">&lt;=</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_38" id="pnum_38">11</a></span> <span class="rm" style="color: #bf0303"><del><em>Mandates</em></del></span> <span class="addu"><em>Constraints</em></span>: <code class="sourceCode cpp">get<span class="op">&lt;</span>i<span class="op">&gt;(</span>v<span class="op">)</span> <span class="op">&gt;=</span> get<span class="op">&lt;</span>i<span class="op">&gt;(</span>w<span class="op">)</span></code> is a valid expression that is convertible to <code class="sourceCode cpp"><span class="dt">bool</span></code>, for all <code class="sourceCode cpp">i</code>.</p>
</blockquote>
<h2 data-number="3.1" id="feature-test-macro"><span class="header-section-number">3.1</span> Feature-test macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>We don’t have a feature-test macro for <code class="sourceCode cpp">std<span class="op">::</span>reference_wrapper<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, and there doesn’t seem like a good one to bump for this, so let’s add a new one to <span>17.3.2 <a href="https://wg21.link/version.syn">[version.syn]</a></span></p>
<blockquote>
<div>
<div class="sourceCode" id="cb20"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb20-1"><a href="#cb20-1"></a><span class="va">+ #define __cpp_lib_reference_wrapper 20XXXXL // freestanding, also in &lt;functional&gt;</span></span></code></pre></div>
</div>
</blockquote>
<p>Likewise, let’s add a new one for the other standard library types described above:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb21"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb21-1"><a href="#cb21-1"></a><span class="va">+ #define __cpp_lib_constrained_equality 20XXXXL // freestanding, also in &lt;utility&gt;, &lt;tuple&gt;, &lt;optional&gt;, &lt;variant&gt;</span></span></code></pre></div>
</div>
</blockquote>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">4</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-P1614R2">
<p>[P1614R2] Barry Revzin. 2019-07-28. The Mothership Has Landed: Adding &lt;=&gt; to the Library. <br />
<a href="https://wg21.link/p1614r2">https://wg21.link/p1614r2</a></p>
</div>
<div id="ref-P2944R0">
<p>[P2944R0] Barry Revzin. 2023-07-09. Comparisons for reference_wrapper. <br />
<a href="https://wg21.link/p2944r0">https://wg21.link/p2944r0</a></p>
</div>
<div id="ref-P2944R1">
<p>[P2944R1] Barry Revzin. 2023-08-17. Comparisons for reference_wrapper. <br />
<a href="https://wg21.link/p2944r1">https://wg21.link/p2944r1</a></p>
</div>
<div id="ref-P2944R2">
<p>[P2944R2] Barry Revzin. 2023-09-17. Comparisons for reference_wrapper. <br />
<a href="https://wg21.link/p2944r2">https://wg21.link/p2944r2</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
