<!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="2025-02-21" />
  <title>Constexpr Type Ordering</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.csl-block{margin-left: 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; }
      .sourceCode { overflow: visible; }
      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;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
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>
  <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">Constexpr Type Ordering</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2830R10</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-02-21</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>
      CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Nate Nichols<br>&lt;<a href="mailto:natenichols@cox.net" class="email">natenichols@cox.net</a>&gt;<br>
      Gašper Ažman<br>&lt;<a href="mailto:gasper.azman@gmail.com" class="email">gasper.azman@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="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision
History<span></span></a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation<span></span></a>
<ul>
<li><a href="#motivating-examples" id="toc-motivating-examples"><span class="toc-section-number">3.1</span> Motivating
Examples<span></span></a>
<ul>
<li><a href="#archetypal-example-canonicalized-typelist" id="toc-archetypal-example-canonicalized-typelist"><span class="toc-section-number">3.1.1</span> Archetypal example:
canonicalized typelist<span></span></a></li>
<li><a href="#canonicalizing-policy-based-libraries" id="toc-canonicalizing-policy-based-libraries"><span class="toc-section-number">3.1.2</span> Canonicalizing policy-based
libraries<span></span></a></li>
<li><a href="#canonicalized-variant" id="toc-canonicalized-variant"><span class="toc-section-number">3.1.3</span> Canonicalized
variant<span></span></a></li>
<li><a href="#canonicalized-tuple" id="toc-canonicalized-tuple"><span class="toc-section-number">3.1.4</span> Canonicalized
tuple<span></span></a></li>
<li><a href="#api-stability" id="toc-api-stability"><span class="toc-section-number">3.1.5</span> API
stability<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#design-discussion" id="toc-design-discussion"><span class="toc-section-number">4</span> Design discussion<span></span></a>
<ul>
<li><a href="#desirable-properties-of-type-orderx-y" id="toc-desirable-properties-of-type-orderx-y"><span class="toc-section-number">4.1</span> Desirable properties of <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code><span></span></a>
<ul>
<li><a href="#stability" id="toc-stability"><span class="toc-section-number">4.1.1</span> Stability<span></span></a></li>
<li><a href="#free-standing" id="toc-free-standing"><span class="toc-section-number">4.1.2</span>
Free-standing<span></span></a></li>
<li><a href="#self-consistency" id="toc-self-consistency"><span class="toc-section-number">4.1.3</span>
Self-consistency<span></span></a></li>
<li><a href="#reflection-compatibility" id="toc-reflection-compatibility"><span class="toc-section-number">4.1.4</span> Reflection
compatibility<span></span></a></li>
<li><a href="#non-goal-consistency-with-type_infobefore" id="toc-non-goal-consistency-with-type_infobefore"><span class="toc-section-number">4.1.5</span> non-goal: Consistency with <code class="sourceCode cpp">type_info<span class="op">::</span>before<span class="op">()</span></code><span></span></a></li>
</ul></li>
<li><a href="#pros-of-implementation-defined" id="toc-pros-of-implementation-defined"><span class="toc-section-number">4.2</span> Pros of
implementation-defined<span></span></a>
<ul>
<li><a href="#abi-specifications-already-have-to-do-this-work" id="toc-abi-specifications-already-have-to-do-this-work"><span class="toc-section-number">4.2.1</span> ABI specifications already have
to do this work<span></span></a></li>
<li><a href="#the-c-standard-doesnt-own-cross-compilation-unit-semantics" id="toc-the-c-standard-doesnt-own-cross-compilation-unit-semantics"><span class="toc-section-number">4.2.2</span> The C++ standard doesn’t own
cross-compilation-unit semantics<span></span></a></li>
<li><a href="#any-new-proposal-to-c-would-have-to-consider-the-ordering" id="toc-any-new-proposal-to-c-would-have-to-consider-the-ordering"><span class="toc-section-number">4.2.3</span> Any new proposal to C++ would
have to consider the ordering<span></span></a></li>
<li><a href="#type-orderx-y-already-has-public-facing-api-implications" id="toc-type-orderx-y-already-has-public-facing-api-implications"><span class="toc-section-number">4.2.4</span> <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
already has public-facing API implications<span></span></a></li>
</ul></li>
<li><a href="#pros-of-completely-defined-order-not-chosen" id="toc-pros-of-completely-defined-order-not-chosen"><span class="toc-section-number">4.3</span> Pros of completely defined order
(not chosen)<span></span></a>
<ul>
<li><a href="#static-analyzers-do-not-have-a-single-backend" id="toc-static-analyzers-do-not-have-a-single-backend"><span class="toc-section-number">4.3.1</span> Static analyzers do not have a
single backend<span></span></a></li>
<li><a href="#consteval-should-be-as-portable-as-possible" id="toc-consteval-should-be-as-portable-as-possible"><span class="toc-section-number">4.3.2</span>
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
should be as portable as possible<span></span></a></li>
<li><a href="#producing-and-comparing-two-mangled-names-takes-more-memory-to-cache" id="toc-producing-and-comparing-two-mangled-names-takes-more-memory-to-cache"><span class="toc-section-number">4.3.3</span> Producing and comparing two
mangled names takes more memory to cache<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">5</span> Proposal<span></span></a>
<ul>
<li><a href="#semantics" id="toc-semantics"><span class="toc-section-number">5.1</span> Semantics<span></span></a></li>
<li><a href="#proposed-syntax" id="toc-proposed-syntax"><span class="toc-section-number">5.2</span> Proposed Syntax<span></span></a>
<ul>
<li><a href="#discussion" id="toc-discussion"><span class="toc-section-number">5.2.1</span> Discussion<span></span></a></li>
<li><a href="#future-extension" id="toc-future-extension"><span class="toc-section-number">5.2.2</span> Future
extension<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">6</span> Proposed Wording<span></span></a>
<ul>
<li><a href="#notes-on-wording" id="toc-notes-on-wording"><span class="toc-section-number">6.1</span> Notes on
wording<span></span></a></li>
</ul></li>
<li><a href="#faq" id="toc-faq"><span class="toc-section-number">7</span> FAQ<span></span></a>
<ul>
<li><a href="#why-should-this-be-standardized" id="toc-why-should-this-be-standardized"><span class="toc-section-number">7.1</span> Why should this be
standardized?<span></span></a></li>
<li><a href="#why-not-wait-for-reflection" id="toc-why-not-wait-for-reflection"><span class="toc-section-number">7.2</span> Why not wait for
reflection?<span></span></a></li>
<li><a href="#but-couldnt-this-be-done-faster-with-reflection" id="toc-but-couldnt-this-be-done-faster-with-reflection"><span class="toc-section-number">7.3</span> But couldn’t this be done faster
with reflection?<span></span></a></li>
</ul></li>
<li><a href="#implementability" id="toc-implementability"><span class="toc-section-number">8</span>
Implementability<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">9</span>
Acknowledgements<span></span></a></li>
<li><a href="#appendix-a-discarded-syntax-options" id="toc-appendix-a-discarded-syntax-options"><span class="toc-section-number">10</span> Appendix A: Discarded syntax
options<span></span></a>
<ul>
<li><a href="#variable-template-stdentity_orderingx-y" id="toc-variable-template-stdentity_orderingx-y"><span class="toc-section-number">10.1</span> variable template <code class="sourceCode cpp">std<span class="op">::</span>entity_ordering<span class="op">&lt;</span>X, Y<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#reflection" id="toc-reflection"><span class="toc-section-number">10.2</span> reflection<span></span></a></li>
<li><a href="#heterogeneous-constexpr-stdtype_identityoperator-bad" id="toc-heterogeneous-constexpr-stdtype_identityoperator-bad"><span class="toc-section-number">10.3</span> heterogeneous <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>type_identity<span class="op">::</span><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
(bad)<span></span></a></li>
<li><a href="#constexpr-std__liftargoperator-bad" id="toc-constexpr-std__liftargoperator-bad"><span class="toc-section-number">10.4</span> <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>__lift<span class="op">&lt;</span>arg<span class="op">&gt;::</span><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
(bad)<span></span></a></li>
<li><a href="#non-option-constexpr-bool-stdtype_infobefore" id="toc-non-option-constexpr-bool-stdtype_infobefore"><span class="toc-section-number">10.5</span> Non-Option: <code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">bool</span> std<span class="op">::</span>type_info<span class="op">::</span>before<span class="op">()</span></code><span></span></a></li>
</ul></li>
<li><a href="#appendix-b-building-apply_canonicalized" id="toc-appendix-b-building-apply_canonicalized"><span class="toc-section-number">11</span> Appendix B: building
<code class="sourceCode cpp">apply_canonicalized</code><span></span></a>
<ul>
<li><a href="#full-code-listing-as-tested-and-implemented" id="toc-full-code-listing-as-tested-and-implemented"><span class="toc-section-number">11.1</span> Full code listing as tested and
implemented<span></span></a></li>
</ul></li>
<li><a href="#appendix-c-__pretty_function__-instability" id="toc-appendix-c-__pretty_function__-instability"><span class="toc-section-number">12</span> Appendix C: <code class="sourceCode cpp"><span class="ot">__PRETTY_FUNCTION__</span></code>
instability<span></span></a></li>
<li><a href="#appendix-d-proscons-slide-from-ewg-wroclaw" id="toc-appendix-d-proscons-slide-from-ewg-wroclaw"><span class="toc-section-number">13</span> Appendix D: pros/cons slide from
EWG Wroclaw<span></span></a></li>
<li><a href="#appendix-zzz-this-his-how-deep-the-rabbit-hole-goes" id="toc-appendix-zzz-this-his-how-deep-the-rabbit-hole-goes"><span class="toc-section-number">14</span> Appendix ZZZ: This his how deep the
rabbit hole goes<span></span></a>
<ul>
<li><a href="#foreword" id="toc-foreword"><span class="toc-section-number">14.1</span> Foreword<span></span></a></li>
<li><a href="#approach" id="toc-approach"><span class="toc-section-number">14.2</span> Approach<span></span></a></li>
<li><a href="#structure-of-sort-key-tuples" id="toc-structure-of-sort-key-tuples"><span class="toc-section-number">14.3</span> Structure of
sort-key-tuples<span></span></a></li>
<li><a href="#decl-scopes" id="toc-decl-scopes"><span class="toc-section-number">14.4</span> decl-scopes<span></span></a>
<ul>
<li><a href="#every-declaration-introduces-a-decl-scope." id="toc-every-declaration-introduces-a-decl-scope."><span class="toc-section-number">14.4.1</span> Every declaration introduces a
decl-scope.<span></span></a></li>
</ul></li>
<li><a href="#what-to-do-with-undefined-comparisons" id="toc-what-to-do-with-undefined-comparisons"><span class="toc-section-number">14.5</span> What to do with undefined
comparisons?<span></span></a></li>
<li><a href="#modules" id="toc-modules"><span class="toc-section-number">14.6</span> Modules<span></span></a></li>
<li><a href="#namespaces" id="toc-namespaces"><span class="toc-section-number">14.7</span> Namespaces<span></span></a>
<ul>
<li><a href="#the-global-namespace" id="toc-the-global-namespace"><span class="toc-section-number">14.7.1</span> The global
namespace<span></span></a></li>
<li><a href="#named-namespaces" id="toc-named-namespaces"><span class="toc-section-number">14.7.2</span> Named
namespaces<span></span></a></li>
<li><a href="#the-anonymous-namespace" id="toc-the-anonymous-namespace"><span class="toc-section-number">14.7.3</span> The anonymous
namespace<span></span></a></li>
<li><a href="#namespace-examples" id="toc-namespace-examples"><span class="toc-section-number">14.7.4</span> Namespace
examples<span></span></a></li>
</ul></li>
<li><a href="#cv-qualified-types" id="toc-cv-qualified-types"><span class="toc-section-number">14.8</span> cv-qualified
types<span></span></a>
<ul>
<li><a href="#qualifiers" id="toc-qualifiers"><span class="toc-section-number">14.8.1</span>
Qualifiers<span></span></a></li>
<li><a href="#scalar-types" id="toc-scalar-types"><span class="toc-section-number">14.8.2</span> Scalar
Types<span></span></a></li>
<li><a href="#array-types" id="toc-array-types"><span class="toc-section-number">14.8.3</span> Array
Types<span></span></a></li>
<li><a href="#expressions" id="toc-expressions"><span class="toc-section-number">14.8.4</span>
Expressions<span></span></a></li>
<li><a href="#lambdas" id="toc-lambdas"><span class="toc-section-number">14.8.5</span> Lambdas<span></span></a></li>
</ul></li>
<li><a href="#old-design-that-needs-to-be-revamped" id="toc-old-design-that-needs-to-be-revamped"><span class="toc-section-number">14.9</span> Old design that needs to be
revamped<span></span></a>
<ul>
<li><a href="#example-1-class-foo-is-declared-in-struct-bar" id="toc-example-1-class-foo-is-declared-in-struct-bar"><span class="toc-section-number">14.9.1</span> Example 1:
<code class="sourceCode cpp"><span class="kw">class</span> foo</code> is
declared in
<code class="sourceCode cpp"><span class="kw">struct</span> bar</code>:<span></span></a></li>
<li><a href="#example" id="toc-example"><span class="toc-section-number">14.9.2</span> Example:<span></span></a></li>
</ul></li>
<li><a href="#atoms" id="toc-atoms"><span class="toc-section-number">14.10</span> Atoms<span></span></a></li>
<li><a href="#identifiers" id="toc-identifiers"><span class="toc-section-number">14.11</span>
identifiers<span></span></a></li>
<li><a href="#kinds" id="toc-kinds"><span class="toc-section-number">14.12</span> Kinds<span></span></a>
<ul>
<li><a href="#identifiers-1" id="toc-identifiers-1"><span class="toc-section-number">14.12.1</span>
Identifiers<span></span></a></li>
<li><a href="#namespaces-1" id="toc-namespaces-1"><span class="toc-section-number">14.12.2</span>
Namespaces<span></span></a></li>
<li><a href="#types" id="toc-types"><span class="toc-section-number">14.12.3</span> Types<span></span></a></li>
<li><a href="#ordering-class-types" id="toc-ordering-class-types"><span class="toc-section-number">14.12.4</span> Ordering Class
Types<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">15</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>As of C++23, <code class="sourceCode cpp">std<span class="op">::</span>type_info</code>
provides a stable but <em>unspecified</em> and
non-<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
order on types.</p>
<p>This paper explores a standardized, constexpr ordering of types in
C++.</p>
<p>This paper is split into two parts:</p>
<ol type="1">
<li>the design of the exposition-only function <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code>,
which deals with how such an order should be defined,</li>
<li>how to expose this capability to the programmer (syntax).</li>
</ol>
<h1 data-number="2" id="revision-history"><span class="header-section-number">2</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<ol start="0" type="1">
<li>New Paper</li>
<li>Revision 1
<ul>
<li>Introduce options to prevent changing <code class="sourceCode cpp">std<span class="op">::</span>type_info<span class="op">::</span>before</code></li>
<li>Anonymous namespaces can’t be empty</li>
<li>Add FAQ section</li>
<li>Add motivating examples</li>
<li>Add proposed syntax</li>
<li>Add appendix</li>
</ul></li>
<li>Revision 2
<ul>
<li>Presented at the EWGi in Tokyo.</li>
<li>Propose to make the <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
definition
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
and <em>implementation-defined</em>, as suggested by EWGi and BSI
reviewers.</li>
<li>added wording</li>
<li>added more motivating examples</li>
</ul></li>
<li>Revision 3
<ul>
<li>incorporates wording feedback from Jens Maurer, to be presented in
an EWG telecon</li>
</ul></li>
<li>Revision 4
<ul>
<li>incorporated feedback from the EWG discussion on May 17th</li>
<li>Added example of <code class="sourceCode cpp"><span class="ot">__PRETTY_FUNCTION__</span></code>
differences from Barry Revzin (thanks!)</li>
<li>Incorporated the fact that EWG decided that the syntax is
reasonable, pending LEWG review.</li>
<li>Did a further pass on properly defining <code class="sourceCode cpp">SORT_KEY<span class="op">(</span>x, y<span class="op">)</span></code></li>
</ul></li>
<li>Revision 5
<ul>
<li>did a lot more work on what we would need to standardize if we
wanted to completely define the ordering.</li>
<li>presented to SG7 in Wroclaw, they said they want to fully define
it</li>
<li>presented to EWG in Wroclaw, they forwarded with strong consensus to
leave it implementation defined</li>
<li>wrote wording and relegated the sketch of the completely-defined
order to a historical appendix</li>
</ul></li>
<li>Revision 6
<ul>
<li>added feature-test macro</li>
</ul></li>
<li>Revision 7
<ul>
<li>more wording fixes.</li>
</ul></li>
<li>Revision 8
<ul>
<li>Wording fixes from Jeff Garland, Jens Maurer, Tomasz Kamiński and
Tim Song on the lwg mailing list.</li>
</ul></li>
<li>Revision 9
<ul>
<li>Editorial wording fixes from LWG review.</li>
</ul></li>
<li>Revision 10:
<ul>
<li>Wording fixes from Hubert Tong.</li>
</ul></li>
</ol>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>There is currently no way in portable C++ to sort types at
compile-time.</p>
<p>Various libraries hack it together, mostly by utilizing <code class="sourceCode cpp"><span class="ot">__PRETTY_FUNCTION__</span></code>,
but all such methods are non-portable and error-prone (consider
forward-declared enums - example in Annex). There are multiple
stack-overflow questions on the topic.</p>
<p><a href="https://github.com/libfn/functional">One such
implementation</a> is part of the monadic functional library by Bronek
Kozicki et al.</p>
<p>Fundamentally, we need a way to canonicalize sets and multisets of
types. This is necessary when building any kind of compositional library
in C++, from <code class="sourceCode cpp">std<span class="op">::</span>execution</code>
<span class="citation" data-cites="P2300R7">[<a href="https://wg21.link/p2300r7" role="doc-biblioref">P2300R7</a>]</span>, mixin libraries, libraries of
monadic components and operators, policy-based libraries, etc. The
inability to sort and unique types leads to the instantiation of an
combinatorial number of templates instead of just one per typeset, which
leads to code-bloat and untenable compile-times. The problem is
fundamentally that without typeset canonicalization, we generate
different template specializations but equivalent behavior, and there is
no way to avoid this.</p>
<p>The goal here is to provide a <em>flexible</em> language mechanism to
let both <code class="sourceCode cpp">Foo<span class="op">&lt;</span>A, B, C<span class="op">&gt;</span></code>
and <code class="sourceCode cpp">Foo<span class="op">&lt;</span>C, B, A<span class="op">&gt;</span></code>
produce the same underlying <code class="sourceCode cpp">Foo_impl<span class="op">&lt;</span>A, B, C<span class="op">&gt;</span></code>.</p>
<p>The reason we start with <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">()</span></code>
and not “just give me typesets” is that we need flexibility;
consider</p>
<ul>
<li>a given library might want to deduplicate on a part and keep either
last or first, or even make it ill-formed: <code class="sourceCode cpp">Foo<span class="op">&lt;</span>pair<span class="op">&lt;</span>A, X<span class="op">&gt;</span>, pair<span class="op">&lt;</span>B, Y<span class="op">&gt;</span>, pair<span class="op">&lt;</span>A, Z<span class="op">&gt;&gt;</span></code>
might want to be the same as <code class="sourceCode cpp">Foo_impl<span class="op">&lt;</span>pair<span class="op">&lt;</span>A, X<span class="op">&gt;</span>, pair<span class="op">&lt;</span>B, Y<span class="op">&gt;&gt;</span></code>
or <code class="sourceCode cpp">Foo_impl<span class="op">&lt;</span>pair<span class="op">&lt;</span>A, Z<span class="op">&gt;</span>, pair<span class="op">&lt;</span>B, Y<span class="op">&gt;&gt;</span></code></li>
<li>a given library might actually just want canonicalized multisets:
<code class="sourceCode cpp">Foo<span class="op">&lt;</span>A, B, A, A, C<span class="op">&gt;</span></code>
should perhaps be <code class="sourceCode cpp">Foo<span class="op">&lt;</span>A, A, A, B, C<span class="op">&gt;</span></code></li>
<li>or treat the first one as special: <code class="sourceCode cpp">Matrix<span class="op">&lt;</span><span class="dt">float</span>, policy1, policy2, policy3<span class="op">&gt;</span></code>
should only deduplicate policies.</li>
</ul>
<p>We must provide
<code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER</code>
in order to <code class="sourceCode cpp">sort</code> and
<code class="sourceCode cpp">unique</code>; they are required building
blocks for any <code class="sourceCode cpp">set</code> primitive. Put
another way, even if we standardized a
<code class="sourceCode cpp">set</code>, we’d need to somehow
canonicalize the order (due to mangling and debug info), leading us back
here.</p>
<p>Without such canonicalization, it is infeasible to enumerate the set
of function templates to instantiate in a separate compilation unit. For
the same reason, it’s utterly impossible to type-erase them in a
fixed-size virtual function table.</p>
<h2 data-number="3.1" id="motivating-examples"><span class="header-section-number">3.1</span> Motivating Examples<a href="#motivating-examples" class="self-link"></a></h2>
<p>This section introduces the kind of code we would like to write,
regardless of how this feature ends up being spelled. To not prejudice
the reader in this section, please assume the existence of an
exposition-only
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
macro <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>strong_ordering</code>
whose arguments can be any cv-ref qualified types.</p>
<p><strong>Note:</strong> while <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code>
is defined on types, we can define a set of class templates that take an
arbitrary template argument, and
<code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER</code>
those; this induces an order on all entities that can be template
arguments.</p>
<p>Crucially, also consider the interactions with <span class="citation" data-cites="P1985R3">[<a href="https://wg21.link/p1985r3" role="doc-biblioref">P1985R3</a>]</span> and <span class="citation" data-cites="P2841R1">[<a href="https://wg21.link/p2841r1" role="doc-biblioref">P2841R1</a>]</span>, which introduce
<code class="sourceCode cpp"><span class="kw">concept</span></code> and
<code class="sourceCode cpp">variable<span class="op">-</span><span class="kw">template</span></code>
arguments.</p>
<h3 data-number="3.1.1" id="archetypal-example-canonicalized-typelist"><span class="header-section-number">3.1.1</span> Archetypal example:
canonicalized typelist<a href="#archetypal-example-canonicalized-typelist" class="self-link"></a></h3>
<p>(Kept short because further examples give concrete needs).</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A <span class="op">{}</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">{}</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="co">// we want some way to enable</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>typeset<span class="op">&lt;</span>A, B<span class="op">&gt;</span>, typeset<span class="op">&lt;</span>B, A, A<span class="op">&gt;&gt;)</span>;</span></code></pre></div>
<p>Furthermore, we need the order to be the same in different
compilation units.</p>
<h3 data-number="3.1.2" id="canonicalizing-policy-based-libraries"><span class="header-section-number">3.1.2</span> Canonicalizing policy-based
libraries<a href="#canonicalizing-policy-based-libraries" class="self-link"></a></h3>
<p>Consider the needs of a library for type-erasure; we’d like the user
to specify the capabilities to erase. Fundamentally, these capabilities
are a set.</p>
<p>Observe:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> T1 <span class="op">=</span> lib<span class="op">::</span>dyn<span class="op">&lt;</span>ostreamable, json_serializable, iterable<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, scalar_multiplicable<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>Different users of the library will likely provide these capabilities
in different orders; this becomes especially problematic when writing
functions:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> T2 <span class="op">=</span> lib<span class="op">::</span>dyn<span class="op">&lt;</span>json_serializable, ostreamable, iterable<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, scalar_multiplicable<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>                    <span class="op">~~~~~~</span> flipped <span class="op">~~~~~~~~~~~~~~~</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">(</span>T2 <span class="kw">const</span><span class="op">&amp;)</span>;</span></code></pre></div>
<p>We can solve this by having type aliases, but if these sets are
<em>computed</em>, we are left without recourse:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> sum <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> pipeline1 <span class="op">=</span> </span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>   log<span class="op">(</span>std<span class="op">::</span>cerr<span class="op">)</span> <span class="op">|</span> sum_into<span class="op">(&amp;</span>sum<span class="op">)</span> <span class="op">|</span> imul<span class="op">(</span>sum<span class="op">)</span> <span class="op">|</span> json_dump<span class="op">(</span>std<span class="op">::</span>cout<span class="op">)</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">// dyn&lt;ostreamable, iterable&lt;int&gt;, scalar_multiplicable&lt;int&gt;, json_serializable&gt;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> pipeline2 <span class="op">=</span> </span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>   sum_into<span class="op">(&amp;</span>sum<span class="op">)</span> <span class="op">|</span> imul<span class="op">(</span>sum<span class="op">)</span> <span class="op">|</span> json_dump<span class="op">(</span>std<span class="op">::</span>cout<span class="op">)</span> <span class="op">|</span> log<span class="op">(</span>std<span class="op">::</span>cerr<span class="op">)</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">// dyn&lt;iterable&lt;int&gt;, scalar_multiplicable&lt;int&gt;, json_serializable, ostreamable&gt;</span></span></code></pre></div>
<p>The above pipelines need the same type-erased interface for its
input, and neither is either <code class="sourceCode cpp">T1</code> or
<code class="sourceCode cpp">T2</code>.</p>
<h3 data-number="3.1.3" id="canonicalized-variant"><span class="header-section-number">3.1.3</span> Canonicalized variant<a href="#canonicalized-variant" class="self-link"></a></h3>
<p>The most obvious example is a canonicalized
<code class="sourceCode cpp">std<span class="op">::</span>variant</code>,
that is, something like</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> variant_for <span class="op">=</span> apply_canonicalized<span class="op">&lt;</span>std<span class="op">::</span>variant, Ts<span class="op">...&gt;</span>;</span></code></pre></div>
<p>Building <code class="sourceCode cpp">apply_canonicalized</code> is
not terribly difficult, as long as we have
<code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER</code>.
Please see the appendices on how to do it.</p>
<p>It <em>would</em> be nice if
<code class="sourceCode cpp">apply_canonicalized</code> was a language
built-in, but to do that, we need to first define <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code>.
After we define
<code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER</code>,
putting <code class="sourceCode cpp">apply_canonicalized</code> into
<code class="sourceCode cpp">type_traits</code> is a far simpler
proposition.</p>
<p><strong>Note:</strong>
<code class="sourceCode cpp">apply_canonicalized</code> is roughly <code class="sourceCode cpp">mp11<span class="op">::</span>mp_sort</code> +
<code class="sourceCode cpp">mp11<span class="op">::</span>unique</code>
with the order derived from
<code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER</code>.</p>
<p>Effectively any time a variant is type-indexed instead of
integer-indexed, we would prefer the compiler generate just one type per
set, instead of type-per-list.</p>
<p>Examples follow, but they are by no means exhaustive.</p>
<h4 data-number="3.1.3.1" id="multiple-error-kinds-and-stdexpected"><span class="header-section-number">3.1.3.1</span> Multiple error kinds and
<code class="sourceCode cpp">std<span class="op">::</span>expected</code><a href="#multiple-error-kinds-and-stdexpected" class="self-link"></a></h4>
<p>Consider a <code class="sourceCode cpp">std<span class="op">::</span>expected</code> for
an algorithm that can fail in several ways:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> read_packet<span class="op">(</span>socket<span class="op">&amp;</span> sock<span class="op">)</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> expected<span class="op">&lt;</span>message, variant<span class="op">&lt;</span>io_error, decode_error<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>Such an algorithm doesn’t care about whether the error type is <code class="sourceCode cpp">variant<span class="op">&lt;</span>io_error, decode_error<span class="op">&gt;</span></code>
or <code class="sourceCode cpp">variant<span class="op">&lt;</span>decode_error, io_error<span class="op">&gt;</span></code>.
This is not as much of a problem in cases where the programmer writes
the types by hand, but consider the generic situation where several
errors must be aggregated generically:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Decoder<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> read_packet<span class="op">(</span>socket<span class="op">&amp;</span> sock<span class="op">)</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> expected<span class="op">&lt;</span>Decoder<span class="op">::</span>message_type,</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>                variant<span class="op">&lt;</span><span class="co">/*uniqued and sorted io_error + Decoder::error_types*/</span><span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>If we had member packs and pack aliases, and a nice built-in
<code class="sourceCode cpp">set</code>, we could o the above as</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">...</span><span class="kw">using</span> set <span class="op">=</span> <span class="fu">__builtin_uniqued_sorted</span><span class="op">&lt;</span>Ts<span class="op">...&gt;</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>variant<span class="op">&lt;...</span>set<span class="op">&lt;</span>io_error, Decoder<span class="op">::...</span>error_types<span class="op">...&gt;...&gt;</span>;</span></code></pre></div>
<h4 data-number="3.1.3.2" id="suspension-point-storage-for-asynchronous-code"><span class="header-section-number">3.1.3.2</span> Suspension-point storage
for asynchronous code<a href="#suspension-point-storage-for-asynchronous-code" class="self-link"></a></h4>
<p><code class="sourceCode cpp">std<span class="op">::</span>execution</code>
(and every other async library) needs a variant-type to store the
current result at a suspension point. In general, since it models a
“suspended” function call, it’s analogous to some kind of</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>variant<span class="op">&lt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    closure_tuple<span class="op">&lt;</span>set_value, Arg1_1, Arg1_2, Arg1_3<span class="op">&gt;</span>, <span class="co">// first possible entry point</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    closure_tuple<span class="op">&lt;</span>set_value, Arg2_1<span class="op">&gt;</span>,                 <span class="co">// second possible entry point</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    closure_tuple<span class="op">&lt;</span>set_error, <span class="op">...&gt;</span>,</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span></span></code></pre></div>
<p>The venerable <code class="sourceCode cpp">rxcpp</code> library by
Kirk Shoop calls this type a <em>notification</em>.</p>
<p>Consider the <code class="sourceCode cpp">transfer<span class="op">(</span>scheduler<span class="op">)</span></code>
algorithm; it receives all <code class="sourceCode cpp">set_value<span class="op">(</span>PACK<span class="op">)</span></code>,
<code class="sourceCode cpp">set_error<span class="op">(</span>PACK<span class="op">)</span></code>
and possibly <code class="sourceCode cpp">set_stopped<span class="op">()</span></code>
parameter lists, <em>stores them in a</em> <code class="sourceCode cpp">variant<span class="op">&lt;</span>tuple<span class="op">&lt;</span>CHANNEL, PACK<span class="op">&gt;...&gt;</span></code>,
and resumes with the values on a different scheduler once the compute
resource becomes available.</p>
<p>The code using it looks like this:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>some_computation <span class="op">|</span> transfer<span class="op">(</span>scheduler<span class="op">)</span> <span class="op">|</span> then<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;...</span>args<span class="op">){</span><span class="co">/*...*/</span><span class="op">})...</span></span></code></pre></div>
<p>All the possible closure tuples are fundamentally unsorted, and
generating the assembly, debug information, and everything else for this
type more than once is a waste of compile-time and executable space (as
well as instruction cache).</p>
<p>Furthermore, stamping out this type multiple times also duplicates
the calling code, and given the different indices, COMDAT folding cannot
deduplicate those code-paths.</p>
<h4 data-number="3.1.3.3" id="compositional-state-machine-models"><span class="header-section-number">3.1.3.3</span> Compositional State machine
models<a href="#compositional-state-machine-models" class="self-link"></a></h4>
<p>The states of most state-machines are fundamentally unordered, as are
the message types they receive. If a state machine is generated (such as
in a compile-time regex library), canonicalizing identically-behaving
components would lead to smaller state-machines and faster compile- and
execution times.</p>
<h3 data-number="3.1.4" id="canonicalized-tuple"><span class="header-section-number">3.1.4</span> Canonicalized tuple<a href="#canonicalized-tuple" class="self-link"></a></h3>
<p>Similarly to a canonicalized
<code class="sourceCode cpp">variant</code>, a
<code class="sourceCode cpp">canonicalized_tuple</code> could be
implemented as</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span>Ts<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> canonical_tuple <span class="op">=</span> apply_canonicalized<span class="op">&lt;</span>tuple, Ts<span class="op">...&gt;</span>;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co">// or</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> canonical_tuple <span class="op">=</span> tuple<span class="op">&lt;...</span>set<span class="op">&lt;</span>Ts<span class="op">...&gt;...&gt;</span>;</span></code></pre></div>
<p>This is far less useful on its own than the
<code class="sourceCode cpp">variant</code>, since initializing that
type will be quite the chore. Instead, canonicalized tuples appear as a
result of the <code class="sourceCode cpp">environment</code>
monads.</p>
<p><code class="sourceCode cpp">std<span class="op">::</span>execution</code>
mixes in an environment, which consists at least of a
<code class="sourceCode cpp">stoppable_token</code>, a
<code class="sourceCode cpp">scheduler</code>, and possibly other things
like a <code class="sourceCode cpp">domain</code>, and, at least in the
authors’ implementation, arbitrary other things. An
<code class="sourceCode cpp">allocator</code> is also optionally part of
the environment.</p>
<p>The <code class="sourceCode cpp">environment<span class="op">&lt;</span>pair<span class="op">&lt;</span>Tags, Ts<span class="op">&gt;...&gt;</span></code>
is a product type that is a map from
<code class="sourceCode cpp">Tag</code> to a value of type
<code class="sourceCode cpp">T</code>, say <code class="sourceCode cpp">std<span class="op">::</span>stop_token</code> to
<code class="sourceCode cpp">never_stop_token<span class="op">{}</span></code>
and <code class="sourceCode cpp">scheduler</code> to
<code class="sourceCode cpp">thread_pool_scheduler</code>.</p>
<p>One can push and pop things off the environment in different parts of
the pipeline; if the pushes come in the wrong order, the environment is
difficult to keep canonicalized.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> ss <span class="op">=</span> std<span class="op">::</span>stop_source<span class="op">()</span>;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> tp <span class="op">=</span> std<span class="op">::</span>static_thread_pool<span class="op">(</span><span class="dv">5</span><span class="op">)</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> env <span class="op">=</span> empty_env<span class="op">{}</span> </span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> push_env<span class="op">&lt;</span>stop_token<span class="op">&gt;(</span>ss<span class="op">.</span>get_token<span class="op">())</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> push_env<span class="op">&lt;</span>scheduler_t<span class="op">&gt;(</span>tp<span class="op">.</span>get_scheduler<span class="op">())</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">|</span> push_env<span class="op">&lt;</span>mylib<span class="op">::</span>numa_domain_t<span class="op">&gt;(</span><span class="dv">2</span><span class="op">)</span>;</span></code></pre></div>
<p>If you imagine those three calls to happen in different algorithm
transformers, it’s quite likely they’ll be in a different order,
manifesting a different type, which doesn’t make much sense - the type
behaves identically, this just leads to code bloat.</p>
<h3 data-number="3.1.5" id="api-stability"><span class="header-section-number">3.1.5</span> API stability<a href="#api-stability" class="self-link"></a></h3>
<p>The authors have observed a necessity to sometimes split parts of
such pipeline compositions into different compilation units due to
excessive compile times and repetitive compilation.</p>
<p>This has proven difficult due to the brittle nature of type ordering
of the names of explicit template specializations involved. By far, the
main culprit has been the lack of a sensible canonicalization of names,
as the order changes far more frequently than the set of types.</p>
<p>Consider:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>do_something()</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    | error_if_odd()          // there is no semantic change</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    | error_if_we_too_long()  // if we flip these lines</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    | ...</span></code></pre></div>
<p>Flipping the lines will flip the two exit error types in the error
list, however.</p>
<p>Having a defined, stable order of types proved invaluable (even if we
did hack the type order manually).</p>
<h1 data-number="4" id="design-discussion"><span class="header-section-number">4</span> Design discussion<a href="#design-discussion" class="self-link"></a></h1>
<p>The first two revisions of this proposal tried to construct a full
type ordering from first principles; EWGi then requested we change to an
implementation-defined order (use the mangler), but EWG subsequently
reversed that decision; SG7 affirmed this decision in Wroclaw, only to
be reversed by EWG again to implementation-defined.</p>
<p>This paper proposes the implementation-defined version.</p>
<h2 data-number="4.1" id="desirable-properties-of-type-orderx-y"><span class="header-section-number">4.1</span> Desirable properties of <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code><a href="#desirable-properties-of-type-orderx-y" class="self-link"></a></h2>
<h3 data-number="4.1.1" id="stability"><span class="header-section-number">4.1.1</span> Stability<a href="#stability" class="self-link"></a></h3>
<p>The order should be the same across compilation units. This is key
for generating ABI-compatible vtables, for instance.</p>
<p>It also should be stable through time. An order based on an
ABI-mangling scheme satisfies this notion, at least.</p>
<h3 data-number="4.1.2" id="free-standing"><span class="header-section-number">4.1.2</span> Free-standing<a href="#free-standing" class="self-link"></a></h3>
<p>The order should be available on freestanding implementations. One
crucial use-case is replacing the exception mechanism on those platforms
with return values of <code class="sourceCode cpp">std<span class="op">::</span>expected</code> or
similar, and compromising that is undesirable.</p>
<h3 data-number="4.1.3" id="self-consistency"><span class="header-section-number">4.1.3</span> Self-consistency<a href="#self-consistency" class="self-link"></a></h3>
<p>The ordering should be self-consistent, that is, for all possible
template arguments <code class="sourceCode cpp">T</code>,
<code class="sourceCode cpp">U</code>, and any unary template
<code class="sourceCode cpp">some_template</code>:</p>
<p><code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>T, U<span class="op">)</span> <span class="op">==</span> TYPE<span class="op">-</span>ORDER<span class="op">(</span>some_template<span class="op">&lt;</span>T<span class="op">&gt;</span>, some_template<span class="op">&lt;</span>U<span class="op">&gt;)</span></code>.</p>
<h3 data-number="4.1.4" id="reflection-compatibility"><span class="header-section-number">4.1.4</span> Reflection compatibility<a href="#reflection-compatibility" class="self-link"></a></h3>
<p>Any <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;=&gt;(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>
should be consistent with this one.</p>
<p>While <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
<span class="citation" data-cites="P2320R0">[<a href="https://wg21.link/p2320r0" role="doc-biblioref">P2320R0</a>]</span> objects can reflect more
entities than just types and values (mainly: expressions), any ordering
defined on them should be finer than this one, and specifically
consistent with it. We should do something that reflection can
subsume.</p>
<p>However, it doesn’t seem like that proposal will define an ordering
on <code class="sourceCode cpp">info</code> objects, and we need this
solved sooner than that.</p>
<h3 data-number="4.1.5" id="non-goal-consistency-with-type_infobefore"><span class="header-section-number">4.1.5</span> non-goal: Consistency with
<code class="sourceCode cpp">type_info<span class="op">::</span>before<span class="op">()</span></code><a href="#non-goal-consistency-with-type_infobefore" class="self-link"></a></h3>
<p>Ideally, whenever <code class="sourceCode cpp"><span class="kw">typeid</span><span class="op">(</span>x<span class="op">).</span>before<span class="op">(</span><span class="kw">typeid</span><span class="op">(</span>y<span class="op">))</span> <span class="op">==</span> <span class="kw">true</span></code>,
then <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>.
The converse obviously cannot be true, since <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span></code>
is finer than the order induced by <code class="sourceCode cpp">type_info<span class="op">::</span>before<span class="op">()</span></code>.</p>
<p>However, the standard currently says</p>
<blockquote>
<p>The names, encoding rule, and collating sequence for types are all
unspecified and may differ between programs.</p>
</blockquote>
<p>Since this paper requires that the order not differ between programs,
exposing this as a normative requirement is impossible without
tightening this wording, which is outside the scope of this paper.</p>
<p>At least at present, some implementations decide this order at
program startup time, so this is not implementable in general.</p>
<h2 data-number="4.2" id="pros-of-implementation-defined"><span class="header-section-number">4.2</span> Pros of
implementation-defined<a href="#pros-of-implementation-defined" class="self-link"></a></h2>
<p>The overwhelming response of people working on implementations, as
well as people sitting on the Itanium ABI standards committee, was that
this is a fool’s errand, and we need only look at the bugreports for the
Itanium ABI to see why. This view won.</p>
<h3 data-number="4.2.1" id="abi-specifications-already-have-to-do-this-work"><span class="header-section-number">4.2.1</span> ABI specifications already
have to do this work<a href="#abi-specifications-already-have-to-do-this-work" class="self-link"></a></h3>
<p>As a taster, consider the following conundrum:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> what_type <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>        <span class="op">[](</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self,</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>           <span class="kw">decltype</span><span class="op">([](</span><span class="kw">decltype</span><span class="op">(</span>self<span class="op">)&amp;){})</span> x <span class="op">=</span> <span class="op">{}){</span> <span class="cf">return</span> x; <span class="op">}())</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>        <span class="co">// ^^ outer ^^ inner</span></span></code></pre></div>
<p>The inner lambda’s “name” is clearly dependent on the outer’s, but it
also goes the other way! The ABI standards already have to deal with
such mangling conundrums, and duplicating their work in the C++ standard
itself seems highly counterproductive, especially since the ABI
standards already accomplish all the stability guarantees we would
want.</p>
<h3 data-number="4.2.2" id="the-c-standard-doesnt-own-cross-compilation-unit-semantics"><span class="header-section-number">4.2.2</span> The C++ standard doesn’t own
cross-compilation-unit semantics<a href="#the-c-standard-doesnt-own-cross-compilation-unit-semantics" class="self-link"></a></h3>
<p>Another problem is that within the C++ standard, we cannot legislate
what happens with orderings between compilation units. Granted, we do
not need this for
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
but we do need it to be stable and make sense, so a certain amount of
common sense will be expected from implementations <em>anyway</em>.</p>
<p>The recommendation was overwhelmingly to just let the order be
implementation-defined, and let the implementations do the sensible
thing.</p>
<h3 data-number="4.2.3" id="any-new-proposal-to-c-would-have-to-consider-the-ordering"><span class="header-section-number">4.2.3</span> Any new proposal to C++ would
have to consider the ordering<a href="#any-new-proposal-to-c-would-have-to-consider-the-ordering" class="self-link"></a></h3>
<p>“punting it off to implementations” saves the C++ standardization
process from having to figure this out for every new proposal that
touches types; implementations, however, already have representation on
the committee, and will veto any truly unimplementable things in this
space.</p>
<h3 data-number="4.2.4" id="type-orderx-y-already-has-public-facing-api-implications"><span class="header-section-number">4.2.4</span> <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
already has public-facing API implications<a href="#type-orderx-y-already-has-public-facing-api-implications" class="self-link"></a></h3>
<p>The “normalized” versions of types will inevitably show up in
function signatures; if different compilers on the same platform
produced different orderings, compilation units from different compilers
would refuse to link, despite both “signatures” beings spelled
identically.</p>
<p>Letting the compiler vendors synchronize based on the mangling scheme
or something equivalently useful is the same forum as the current ABI
discussion forums; it seems the appropriate venue to standardize the
ordering anyay, without making WG21 duplicate the work.</p>
<h2 data-number="4.3" id="pros-of-completely-defined-order-not-chosen"><span class="header-section-number">4.3</span> Pros of completely defined
order (not chosen)<a href="#pros-of-completely-defined-order-not-chosen" class="self-link"></a></h2>
<h3 data-number="4.3.1" id="static-analyzers-do-not-have-a-single-backend"><span class="header-section-number">4.3.1</span> Static analyzers do not have
a single backend<a href="#static-analyzers-do-not-have-a-single-backend" class="self-link"></a></h3>
<p>This proved decisive. Since static analyzers and compilers that
produce intermediate representations before choosing a backend are part
of the ecosystem, it is important to be consistent and not rely on a
particular mangler.</p>
<h3 data-number="4.3.2" id="consteval-should-be-as-portable-as-possible"><span class="header-section-number">4.3.2</span>
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
should be as portable as possible<a href="#consteval-should-be-as-portable-as-possible" class="self-link"></a></h3>
<p>The abstract machine used at constant evaluation time has far fewer
parameters than the runtime one. We should keep them to a minimum, and
type ordering is not a necessary parameter. We should keep
implementations consistent.</p>
<h3 data-number="4.3.3" id="producing-and-comparing-two-mangled-names-takes-more-memory-to-cache"><span class="header-section-number">4.3.3</span> Producing and comparing two
mangled names takes more memory to cache<a href="#producing-and-comparing-two-mangled-names-takes-more-memory-to-cache" class="self-link"></a></h3>
<p>The key-tuples proposed in this paper are recursive; the parts of the
type-tuple merely refer to the tuples of the constituent parts; thus,
they can be independently cached and compared as-needed.</p>
<h1 data-number="5" id="proposal"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<h2 data-number="5.1" id="semantics"><span class="header-section-number">5.1</span> Semantics<a href="#semantics" class="self-link"></a></h2>
<p>Let <code class="sourceCode cpp">X</code> and
<code class="sourceCode cpp">Y</code> be (possibly cv-ref) qualified
types, and <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
be an exposition-only macro.</p>
<p>Then, <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
denotes a constant expression of type <code class="sourceCode cpp">std<span class="op">::</span>strong_ordering</code>.</p>
<ul>
<li><code class="sourceCode cpp">std<span class="op">::</span>same_as<span class="op">&lt;</span>X, Y<span class="op">&gt;</span> <span class="op">==</span> <span class="kw">true</span></code>
if and only if <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>equal</code>.</li>
<li>Otherwise, <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
is either <code class="sourceCode cpp">std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>
or <code class="sourceCode cpp">std<span class="op">::</span>strong_ordering<span class="op">::</span>greater</code>.
Which of those is implementation-defined, subject to the following
semantic constraints.</li>
</ul>
<p>Implementations must define <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
such that it is an ordering, that is, it is transitive and
antisymmetric; that is</p>
<ul>
<li>if <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>,
then <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>Y, X<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>greater</code>
and vice versa</li>
<li>if <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>
and <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>Y, Z<span class="op">)</span> <span class="op">==</span> std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>,
then <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Z<span class="op">)</span></code>
is also <code class="sourceCode cpp">std<span class="op">::</span>strong_ordering<span class="op">::</span>less</code>.</li>
</ul>
<p>Implementations are encouraged, but not required to, make the order
recursively-consistent. In other words:</p>
<p>For any class template <code class="sourceCode cpp"><span class="kw">template</span> <span class="op">&lt;...</span>, <span class="kw">typename</span> Pi, <span class="op">...&gt;</span> <span class="kw">class</span> X</code>,
where <code class="sourceCode cpp">Pi</code> is the
<code class="sourceCode cpp">i</code>-th template argument, and any two
types <code class="sourceCode cpp">T</code> and
<code class="sourceCode cpp">U</code>: <code class="sourceCode cpp">TYPE<span class="op">-</span>ORDER<span class="op">(</span>T, U<span class="op">)</span> <span class="op">==</span> TYPE<span class="op">-</span>ORDER<span class="op">(</span>X<span class="op">&lt;...</span>, T, <span class="op">...&gt;</span>, X<span class="op">&lt;...</span>, U, <span class="op">...&gt;)</span></code>
if only the <code class="sourceCode cpp">i</code>th template argument is
varied.</p>
<p>If an implementation makes the order recursively consistent, it
should document this fact.</p>
<h2 data-number="5.2" id="proposed-syntax"><span class="header-section-number">5.2</span> Proposed Syntax<a href="#proposed-syntax" class="self-link"></a></h2>
<p>EWG affirmed a library name to access the ordering.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co">// &lt;compare&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> std<span class="op">::</span>strong_ordering type_order_v <span class="op">=</span> TYPE<span class="op">-</span>ORDER<span class="op">(</span>T, U<span class="op">)</span>; <span class="co">/* see below */</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> type_order <span class="op">:</span> integral_constant<span class="op">&lt;</span>strong_ordering, type_order_v<span class="op">&lt;</span>T, U<span class="op">&gt;&gt;</span> <span class="op">{}</span>;</span></code></pre></div>
<p>As a special provision for this specific metafunction, we allow the
type arguments for it to be incomplete types.</p>
<h3 data-number="5.2.1" id="discussion"><span class="header-section-number">5.2.1</span> Discussion<a href="#discussion" class="self-link"></a></h3>
<p>This seems like a pretty good choice. It does not need a new keyword,
only depends on <code class="sourceCode cpp"><span class="op">&lt;</span>compare<span class="op">&gt;</span></code>,
and the name seems relatively discoverable.</p>
<p>It’s also freestanding, since it doesn’t depend on <code class="sourceCode cpp"><span class="op">&lt;</span>typeinfo<span class="op">&gt;</span></code>.</p>
<p>We do not want <code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>
to depend on <code class="sourceCode cpp"><span class="op">&lt;</span>compare<span class="op">&gt;</span></code>,
so we put it into <code class="sourceCode cpp"><span class="op">&lt;</span>compare<span class="op">&gt;</span></code>
directly.</p>
<h3 data-number="5.2.2" id="future-extension"><span class="header-section-number">5.2.2</span> Future extension<a href="#future-extension" class="self-link"></a></h3>
<p>Once we have pack aliases, the authors will propose the following two
metafunctions, to be implemented using compiler intrinsics:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co">// as a separate library proposal, once member packs make it</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="op">...</span>typemultiset <span class="op">=</span> <span class="co">/* pack of Ts, sorted by type_order_v */</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="op">...</span>typeset <span class="op">=</span> <span class="co">/* uniqued ...typemultiset&lt;Ts...&gt;... */</span>;</span></code></pre></div>
<h1 data-number="6" id="proposed-wording"><span class="header-section-number">6</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<p>In <span>17.11.1
<a href="https://wg21.link/compare.syn">[compare.syn]</a></span>,
add</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>// [compare.type] type ordering</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>struct type_order;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>constexpr strong_ordering type_order_v = type_order&lt;T, U&gt;::value;</span></code></pre></div>
<!--`buggy editor-->
</blockquote>

</div>
<p>At the end of <span>17.11
<a href="https://wg21.link/cmp">[cmp]</a></span>, just before
<span>17.12
<a href="https://wg21.link/support.coroutine">[support.coroutine]</a></span>,
add:</p>
<div class="add" style="color: #006e28">

<blockquote>
<p><strong>17.11.7: Type Ordering</strong> [compare.type]</p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
There is an implementation-defined total ordering of all types. For any
(possibly incomplete) types
<code class="sourceCode default"><em>X</em></code> and
<code class="sourceCode default"><em>Y</em></code>, the expression
<code class="sourceCode default"><em>TYPE-ORDER</em>(<em>X</em>, <em>Y</em>)</code>
is a constant expression (<span>7.7
<a href="https://wg21.link/expr.const">[expr.const]</a></span>) of type
<code class="sourceCode default">strong_ordering</code> (<span>17.11.2.4
<a href="https://wg21.link/cmp.strongord">[cmp.strongord]</a></span>).
Its value is
<code class="sourceCode default">strong_ordering::less</code> if
<code class="sourceCode default"><em>X</em></code> precedes
<code class="sourceCode default"><em>Y</em></code> in this
implementation-defined total order,
<code class="sourceCode default">strong_ordering::greater</code> if
<code class="sourceCode default"><em>Y</em></code> precedes
<code class="sourceCode default"><em>X</em></code>, and
<code class="sourceCode default">strong_ordering::equal</code> if they
are the same type.</p>
<p>[Note 1: <code class="sourceCode default">int</code>,
<code class="sourceCode default">const int</code> and
<code class="sourceCode default">int&amp;</code> are different types. –
end note]</p>
<p>[Note 2: This ordering need not be consistent with the one induced by
<code class="sourceCode default">type_info::before</code>. – end
note]</p>
<p>[Note 3: The ordering of TU-local types from different translation
units is not observable, because the necessary specialization of
<code class="sourceCode default">type_order</code> is impossible to
name. – end note]</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>struct type_order;</span></code></pre></div>
<!--` buggy editor-->
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">type_order</code> denotes a
<em>Cpp17BinaryTypeTrait</em> (<span>21.3.2
<a href="https://wg21.link/meta.rqmts">[meta.rqmts]</a></span>) with a
base characteristic of <code class="sourceCode default">integral_constant&lt;strong_ordering, <em>TYPE-ORDER</em>(<em>X</em>, <em>Y</em>)&gt;</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Recommended practice</em>: The order should be lexicographical on
parameter-type-lists and template argument lists.</p>
</blockquote>

</div>
<p>Add a feature-test macro into <span>17.3.2
<a href="https://wg21.link/version.syn">[version.syn]</a></span> in
section 2</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>#define __cpp_lib_type_order 2025XXL // also in &lt;compare&gt;</span></code></pre></div>
<!--` buggy editor -->
</blockquote>

</div>
<h2 data-number="6.1" id="notes-on-wording"><span class="header-section-number">6.1</span> Notes on wording<a href="#notes-on-wording" class="self-link"></a></h2>
<ul>
<li>I’d like to thank Lewis Baker and Davis Herring for reminding me
that I should probably make an introductory paragraph.</li>
<li>Davis Herring suggested adding a note to remind readers that
<code class="sourceCode cpp"><span class="dt">int</span></code>, <code class="sourceCode cpp"><span class="kw">const</span> <span class="dt">int</span></code>
and <code class="sourceCode cpp"><span class="dt">int</span><span class="op">&amp;</span></code>
are different types.</li>
<li>Jeff Garland, Tim Song, Tomasz Kamiński and Jens Maurer for their
wording fixes and suggestions.</li>
</ul>
<p>Design note: the reason we do not state a recommended practice of
what to do with function return types is to allow doing <em>whatever the
mangling does</em>, which for the itanium ABI means <em>sort by return
type first, and then by function parameter list</em>. It is feasible for
there to be a mangling that would put the return type last.</p>
<h1 data-number="7" id="faq"><span class="header-section-number">7</span> FAQ<a href="#faq" class="self-link"></a></h1>
<h2 data-number="7.1" id="why-should-this-be-standardized"><span class="header-section-number">7.1</span> Why should this be
standardized?<a href="#why-should-this-be-standardized" class="self-link"></a></h2>
<p>Because we have no way to reliably order types across compilation
units at compile-time.</p>
<h2 data-number="7.2" id="why-not-wait-for-reflection"><span class="header-section-number">7.2</span> Why not wait for reflection?<a href="#why-not-wait-for-reflection" class="self-link"></a></h2>
<p>It’s a good question. However, reflection will do <em>nothing</em>
for this problem by itself; the user will still have to implement
ordering using
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
functions, which have no hope of being as fast as a compiler-provided
built-in.</p>
<p>User-programmed functions also won’t adapt to language evolution;
this feature will.</p>
<p>Finally, sorting is arbitrary; having it be consistent throughout the
software ecosystem is potentially a great enabler of
interoperability.</p>
<h2 data-number="7.3" id="but-couldnt-this-be-done-faster-with-reflection"><span class="header-section-number">7.3</span> But couldn’t this be done
faster with reflection?<a href="#but-couldnt-this-be-done-faster-with-reflection" class="self-link"></a></h2>
<p>No; Peter Dimov shares an interesting anecdote.</p>
<blockquote>
<p>I have in Mp11 the algorithm
<code class="sourceCode cpp">mp_unique</code>, which takes a list of
types and removes the duplicates. In the course of writing the
reflection papers, their authors occasionally took Mp11 code examples
and tried to show how they are elegantly implemented using value-based
reflection metaprogramming.</p>
</blockquote>
<blockquote>
<p>So, you take a <code class="sourceCode cpp">vector<span class="op">&lt;</span>info<span class="op">&gt;</span></code>
that contains types, and then you simply apply the existing algorithm
<code class="sourceCode cpp">std<span class="op">::</span>unique</code>
to it, et voila… oh wait.</p>
</blockquote>
<blockquote>
<p><code class="sourceCode cpp">std<span class="op">::</span>unique</code>
wants a sorted range, and you can’t
<code class="sourceCode cpp">std<span class="op">::</span>sort</code>
the info vector, because info objects aren’t ordered, even when they
refer to types.</p>
</blockquote>
<h1 data-number="8" id="implementability"><span class="header-section-number">8</span> Implementability<a href="#implementability" class="self-link"></a></h1>
<p>The proposal has no questions on whether it <em>can</em> be
implemented - the question is about the definition of the order.</p>
<p>The concerns raised by the implementers so far have been mostly
around having to bring the name mangler from the backend and make it
accessible to the compiler front-end, because the obvious implementation
is to define the comparison result on the mangled type strings; this
option has been rejected by EWG.</p>
<p>Making this order match up with <code class="sourceCode cpp">type_info<span class="op">::</span>before</code>
is a matter of bringing the name mangler for the correct platform to the
frontend.</p>
<p>It is the opinion of the authors that this doesn’t seem to be a
layering violation, as the name mangling for a given platform is
analogous to other platform properties, such as the size and alignment
of pointers.</p>
<p>If a platform does not have a name mangling strategy, <em>any</em>
name mangling scheme will still result in a standards-conforming
implementation; however, after much discussion, it seems a better
direction to completely define the order in the standard itself.</p>
<h1 data-number="9" id="acknowledgements"><span class="header-section-number">9</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to all of the following:</p>
<ul>
<li>Davis Herring for his suggestions on ordering non-type template
parameters.</li>
<li>Ville Voutilainen for his critique of examples, and providing a
simple way of explaining the motivation</li>
<li>Peter Dimov for a helpful anecdote, now in the FAQ.</li>
<li>Erich Keane for for pushing us back to the “implementation-defined”
territory.</li>
<li>Jens Maurer for his thorough review of the initial proposed wording
and his guidance.</li>
<li>Hubert Tong for ensuring the necessary reminders were added to the
core wording as opposed to remaining merely parts of the rationale.</li>
</ul>
<h1 data-number="10" id="appendix-a-discarded-syntax-options"><span class="header-section-number">10</span> Appendix A: Discarded syntax
options<a href="#appendix-a-discarded-syntax-options" class="self-link"></a></h1>
<h2 data-number="10.1" id="variable-template-stdentity_orderingx-y"><span class="header-section-number">10.1</span> variable template <code class="sourceCode cpp">std<span class="op">::</span>entity_ordering<span class="op">&lt;</span>X, Y<span class="op">&gt;</span></code><a href="#variable-template-stdentity_orderingx-y" class="self-link"></a></h2>
<p>Specifically:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>universal <span class="kw">template</span> X, universal <span class="kw">template</span> Y<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> strong_ordering entity_order_v <span class="op">=</span> TYPE<span class="op">-</span>ORDER<span class="op">(</span>X, Y<span class="op">)</span>; <span class="co">/* see below */</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>universal <span class="kw">template</span> X, universal <span class="kw">template</span> Y<span class="op">&gt;</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> entity_order <span class="op">:</span> integral_constant<span class="op">&lt;</span>strong_ordering, entity_order_v<span class="op">&lt;</span>X, Y<span class="op">&gt;&gt;</span> <span class="op">{}</span>;</span></code></pre></div>
<p>This is a better option than Option 1 if we get universal template
parameters, as we really want to also order class templates, not just
types.</p>
<p>However, without universal template parameters, we really don’t have
much of a choice but to reach for Option 1.</p>
<p>The name <code class="sourceCode cpp">entity_order</code> is also
slightly less obvious than
<code class="sourceCode cpp">type_order</code>, but metaprogrammers
shouldn’t have trouble finding either.</p>
<h2 data-number="10.2" id="reflection"><span class="header-section-number">10.2</span> reflection<a href="#reflection" class="self-link"></a></h2>
<p>Specifically:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> std<span class="op">::</span>partial_ordering partial_order<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info x, std<span class="op">::</span>meta<span class="op">::</span>info y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> __comparable<span class="op">(</span>x, y<span class="op">)</span> <span class="op">?</span> TYPE<span class="op">-</span>ORDER<span class="op">(</span>x, y<span class="op">)</span> <span class="op">:</span> std<span class="op">::</span>partial_order<span class="op">::</span>unordered;</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We could standardize a type order as a function on <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
objects in
<code class="sourceCode cpp">std<span class="op">::</span>meta</code>.
However, once we’re in <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
space, it’s more difficult to know which reflections are comparable and
which aren’t, so such a function would need to return a <code class="sourceCode cpp">std<span class="op">::</span>partial_order</code>,
which seems decidedly less desirable.</p>
<p>It also means we’d need to pass the correct kind of reflection into
the ordering function, which is a bit less intuitive than just
<code class="sourceCode cpp"><span class="kw">decltype</span></code> or
just the template parameter that we already have.</p>
<h2 data-number="10.3" id="heterogeneous-constexpr-stdtype_identityoperator-bad"><span class="header-section-number">10.3</span> heterogeneous <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>type_identity<span class="op">::</span><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
(bad)<a href="#heterogeneous-constexpr-stdtype_identityoperator-bad" class="self-link"></a></h2>
<p>Specifically:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>strong_ordering <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>std<span class="op">::</span>type_identity<span class="op">&lt;</span>T<span class="op">&gt;</span>, std<span class="op">::</span>type_identity<span class="op">&lt;</span>U<span class="op">&gt;)</span>;</span></code></pre></div>
<p><strong>Pros:</strong></p>
<ul>
<li>No new names.</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Less discoverable than a new type-trait</li>
<li>Requires template instantiations of <code class="sourceCode cpp">type_identity<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
<code class="sourceCode cpp">type_identity<span class="op">&lt;</span>U<span class="op">&gt;</span></code>,
as well as <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
overload resolution and substitution, which is quite expensive compared
to a single <code class="sourceCode cpp">type_order_v<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>
direct substitution and lookup.</li>
<li>An extra <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
overload in the <code class="sourceCode cpp">std</code> namespace is a
drag on overload resolution</li>
<li>adds <code class="sourceCode cpp"><span class="op">&lt;</span>compare<span class="op">&gt;</span></code>
to <code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>,
since that’s where <code class="sourceCode cpp">type_identity</code>
is</li>
<li>too cute?</li>
<li>doesn’t work for nontypes</li>
</ul>
<h2 data-number="10.4" id="constexpr-std__liftargoperator-bad"><span class="header-section-number">10.4</span> <code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>__lift<span class="op">&lt;</span>arg<span class="op">&gt;::</span><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
(bad)<a href="#constexpr-std__liftargoperator-bad" class="self-link"></a></h2>
<p>This option means we add <code class="sourceCode cpp"><span class="kw">template</span> <span class="op">&lt;</span>universal <span class="kw">template</span><span class="op">&gt;</span> <span class="kw">struct</span> __lift <span class="op">{}</span>;</code>
into <code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>
and define <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
for it.</p>
<p><strong>Pros:</strong></p>
<ul>
<li>… we’ll need a lift sooner or later?</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>all the cons of
<code class="sourceCode cpp">type_identity</code></li>
<li>even more nonobvious</li>
<li>still needs a new name</li>
<li>needs a tutorial to find</li>
</ul>
<h2 data-number="10.5" id="non-option-constexpr-bool-stdtype_infobefore"><span class="header-section-number">10.5</span> Non-Option: <code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="dt">bool</span> std<span class="op">::</span>type_info<span class="op">::</span>before<span class="op">()</span></code><a href="#non-option-constexpr-bool-stdtype_infobefore" class="self-link"></a></h2>
<p>(Included because it’s a common question.)</p>
<p>It would be nice, but alas, operates on <em>cv-unqualified</em>
versions of the referenced type, so it’s not sufficient.</p>
<p><code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>strong_order<span class="op">(</span>std<span class="op">::</span>type_info, std<span class="op">::</span>type_info<span class="op">)</span></code>
has similar issues.</p>
<h1 data-number="11" id="appendix-b-building-apply_canonicalized"><span class="header-section-number">11</span> Appendix B: building
<code class="sourceCode cpp">apply_canonicalized</code><a href="#appendix-b-building-apply_canonicalized" class="self-link"></a></h1>
<p>We will need a small metaprogramming library; a filter is difficult
to do otherwise.</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> undefined;</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span> <span class="kw">struct</span> list <span class="op">{}</span>;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="co">// apply&lt;F, list&lt;Ts...&gt;&gt; -&gt; F&lt;Ts...&gt;</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span>, <span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">extern</span> undefined _apply;</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> F, <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> L,</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>          <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>F<span class="op">&lt;</span>Ts<span class="op">...&gt;</span> _apply<span class="op">&lt;</span>F, L<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> F, <span class="kw">typename</span> List<span class="op">&gt;</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> apply <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_apply<span class="op">&lt;</span>F, List<span class="op">&gt;)</span>;</span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a><span class="co">// concatenate&lt;list&lt;Ts...&gt;, list&lt;Us...&gt;, list&lt;Vs...&gt;&gt; -&gt; list&lt;Ts..., Us..., Vs...&gt;</span></span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">extern</span> undefined _concatenate;</span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span> list<span class="op">&lt;</span>Ts<span class="op">...&gt;</span> _concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts, <span class="kw">typename</span><span class="op">...</span> Us, <span class="kw">typename</span><span class="op">...</span> Lists<span class="op">&gt;</span></span>
<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span>_concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...</span>, Us<span class="op">...&gt;</span>, Lists<span class="op">...&gt;)</span></span>
<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a>    _concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...&gt;</span>, list<span class="op">&lt;</span>Us<span class="op">...&gt;</span>, Lists<span class="op">...&gt;</span>;</span>
<span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> concatenate <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_concatenate<span class="op">&lt;</span>Ts<span class="op">...&gt;)</span>;</span>
<span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a><span class="co">// select: list&lt;T&gt; if true, list&lt;&gt; if false</span></span>
<span id="cb23-22"><a href="#cb23-22" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span> v, <span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _select;</span>
<span id="cb23-23"><a href="#cb23-23" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> list<span class="op">&lt;</span>T<span class="op">&gt;</span> _select<span class="op">&lt;</span><span class="kw">true</span>, T<span class="op">&gt;</span>;</span>
<span id="cb23-24"><a href="#cb23-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-25"><a href="#cb23-25" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span> v, <span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb23-26"><a href="#cb23-26" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> select <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_select<span class="op">&lt;</span>v, T<span class="op">&gt;)</span>;</span></code></pre></div>
<p>Canonicalization is now just a basic not-in-place quicksort-ish
thing:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span><span class="co">/*empty*/</span><span class="op">&gt;</span> <span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _canon;</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> canonicalized <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_canon<span class="op">&lt;</span>Ts<span class="op">...&gt;)</span>;</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="co">// a canonicalized T is just T</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-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="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>list<span class="op">&lt;</span>T<span class="op">&gt;</span> _canon<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>concatenate<span class="op">&lt;</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// canonicalized things less than T</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a>    apply<span class="op">&lt;</span>canonicalized, concatenate<span class="op">&lt;</span>select<span class="op">&lt;(</span>TYPE<span class="op">-</span>ORDER<span class="op">(</span>Ts, T<span class="op">)</span> <span class="op">&lt;</span> <span class="dv">0</span><span class="op">)</span>, Ts<span class="op">&gt;...&gt;&gt;</span>,</span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a>    list<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="co">/*T*/</span>, <span class="co">//                        ~~~~~~~~~~~~~~~~</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// canonicalized things greater than T</span></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a>    apply<span class="op">&lt;</span>canonicalized, concatenate<span class="op">&lt;</span>select<span class="op">&lt;(</span>TYPE<span class="op">-</span>ORDER<span class="op">(</span>Ts, T<span class="op">)</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span>, Ts<span class="op">&gt;...</span> <span class="op">&gt;&gt;</span></span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;</span> <span class="co">//                                     ~~~~~~~~~~~~~~~~</span></span>
<span id="cb24-17"><a href="#cb24-17" aria-hidden="true" tabindex="-1"></a>_canon<span class="op">&lt;</span>T, Ts<span class="op">...&gt;</span>;</span></code></pre></div>
<p>We now have <code class="sourceCode cpp">canonicalized<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code>
- but this still leaves <code class="sourceCode cpp">list</code> as a
special type which we’d rather not expose to the user. Onto
<code class="sourceCode cpp">apply_canonicalized</code>:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> F, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> apply_canonicalized <span class="op">=</span> apply<span class="op">&lt;</span>F, canonicalized<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span></code></pre></div>
<h2 data-number="11.1" id="full-code-listing-as-tested-and-implemented"><span class="header-section-number">11.1</span> Full code listing as tested
and implemented<a href="#full-code-listing-as-tested-and-implemented" class="self-link"></a></h2>
<p>Here for completeness, feel free to skip.</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;compare&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> undefined;</span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#define TYPE</span><span class="op">-</span>ORDER<span class="op">(</span>x,<span class="pp"> </span>y<span class="op">)</span><span class="pp"> </span>type_order_v<span class="op">&lt;</span>x,<span class="pp"> </span>y<span class="op">&gt;</span></span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> X, <span class="kw">typename</span> Y<span class="op">&gt;</span></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">inline</span> std<span class="op">::</span>strong_ordering type_order_v;</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span>, <span class="kw">typename</span><span class="op">&gt;</span></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> undefined _apply;</span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> F, <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> L,</span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a>          <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>F<span class="op">&lt;</span>Ts<span class="op">...&gt;</span> _apply<span class="op">&lt;</span>F, L<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span> <span class="kw">typename</span> F, <span class="kw">typename</span> List<span class="op">&gt;</span></span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> apply <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_apply<span class="op">&lt;</span>F, List<span class="op">&gt;)</span>;</span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a><span class="co">// some user-type</span></span>
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> x<span class="op">&gt;</span></span>
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> value_t <span class="op">:</span> std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>x<span class="op">)</span>, x<span class="op">&gt;</span> <span class="op">{}</span>;</span>
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> x<span class="op">&gt;</span></span>
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> value_t<span class="op">&lt;</span>x<span class="op">&gt;</span> value_v<span class="op">{}</span>;</span>
<span id="cb26-26"><a href="#cb26-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-27"><a href="#cb26-27" aria-hidden="true" tabindex="-1"></a><span class="co">// built-in</span></span>
<span id="cb26-28"><a href="#cb26-28" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> x, <span class="kw">auto</span> y<span class="op">&gt;</span></span>
<span id="cb26-29"><a href="#cb26-29" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">inline</span> std<span class="op">::</span>strong_ordering type_order_v<span class="op">&lt;</span>value_t<span class="op">&lt;</span>x<span class="op">&gt;</span>, value_t<span class="op">&lt;</span>y<span class="op">&gt;&gt;</span> <span class="op">=</span></span>
<span id="cb26-30"><a href="#cb26-30" aria-hidden="true" tabindex="-1"></a>    x <span class="op">&lt;=&gt;</span> y;</span>
<span id="cb26-31"><a href="#cb26-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-32"><a href="#cb26-32" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-33"><a href="#cb26-33" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> list <span class="op">{}</span>;</span>
<span id="cb26-34"><a href="#cb26-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-35"><a href="#cb26-35" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span></span>
<span id="cb26-36"><a href="#cb26-36" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> undefined _concatenate;</span>
<span id="cb26-37"><a href="#cb26-37" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-38"><a href="#cb26-38" aria-hidden="true" tabindex="-1"></a>list<span class="op">&lt;</span>Ts<span class="op">...&gt;</span> _concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span>
<span id="cb26-39"><a href="#cb26-39" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts, <span class="kw">typename</span><span class="op">...</span> Us, <span class="kw">typename</span><span class="op">...</span> Lists<span class="op">&gt;</span></span>
<span id="cb26-40"><a href="#cb26-40" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span>_concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...</span>, Us<span class="op">...&gt;</span>, Lists<span class="op">...&gt;)</span></span>
<span id="cb26-41"><a href="#cb26-41" aria-hidden="true" tabindex="-1"></a>    _concatenate<span class="op">&lt;</span>list<span class="op">&lt;</span>Ts<span class="op">...&gt;</span>, list<span class="op">&lt;</span>Us<span class="op">...&gt;</span>, Lists<span class="op">...&gt;</span>;</span>
<span id="cb26-42"><a href="#cb26-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-43"><a href="#cb26-43" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-44"><a href="#cb26-44" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> concatenate <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_concatenate<span class="op">&lt;</span>Ts<span class="op">...&gt;)</span>;</span>
<span id="cb26-45"><a href="#cb26-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-46"><a href="#cb26-46" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span> v, <span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb26-47"><a href="#cb26-47" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _select;</span>
<span id="cb26-48"><a href="#cb26-48" aria-hidden="true" tabindex="-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="cb26-49"><a href="#cb26-49" aria-hidden="true" tabindex="-1"></a>list<span class="op">&lt;</span>T<span class="op">&gt;</span> _select<span class="op">&lt;</span><span class="kw">true</span>, T<span class="op">&gt;</span>;</span>
<span id="cb26-50"><a href="#cb26-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-51"><a href="#cb26-51" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span> v, <span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb26-52"><a href="#cb26-52" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> select <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_select<span class="op">&lt;</span>v, T<span class="op">&gt;)</span>;</span>
<span id="cb26-53"><a href="#cb26-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-54"><a href="#cb26-54" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...&gt;</span></span>
<span id="cb26-55"><a href="#cb26-55" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _canon;</span>
<span id="cb26-56"><a href="#cb26-56" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-57"><a href="#cb26-57" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> canonicalized <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>_canon<span class="op">&lt;</span>Ts<span class="op">...&gt;)</span>;</span>
<span id="cb26-58"><a href="#cb26-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-59"><a href="#cb26-59" aria-hidden="true" tabindex="-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="cb26-60"><a href="#cb26-60" aria-hidden="true" tabindex="-1"></a>list<span class="op">&lt;</span>T<span class="op">&gt;</span> _canon<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span>
<span id="cb26-61"><a href="#cb26-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-62"><a href="#cb26-62" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb26-63"><a href="#cb26-63" aria-hidden="true" tabindex="-1"></a>concatenate<span class="op">&lt;</span></span>
<span id="cb26-64"><a href="#cb26-64" aria-hidden="true" tabindex="-1"></a>    apply<span class="op">&lt;</span>canonicalized, concatenate<span class="op">&lt;</span>select<span class="op">&lt;(</span>TYPE<span class="op">-</span>ORDER<span class="op">(</span>Ts, T<span class="op">)</span> <span class="op">&lt;</span> <span class="dv">0</span><span class="op">)</span>, Ts<span class="op">&gt;...&gt;&gt;</span>,</span>
<span id="cb26-65"><a href="#cb26-65" aria-hidden="true" tabindex="-1"></a>    list<span class="op">&lt;</span>T<span class="op">&gt;</span>,</span>
<span id="cb26-66"><a href="#cb26-66" aria-hidden="true" tabindex="-1"></a>    apply<span class="op">&lt;</span>canonicalized, concatenate<span class="op">&lt;</span>select<span class="op">&lt;(</span>TYPE<span class="op">-</span>ORDER<span class="op">(</span>Ts, T<span class="op">)</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span>, Ts<span class="op">&gt;...</span> <span class="op">&gt;&gt;</span></span>
<span id="cb26-67"><a href="#cb26-67" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;</span></span>
<span id="cb26-68"><a href="#cb26-68" aria-hidden="true" tabindex="-1"></a>_canon<span class="op">&lt;</span>T, Ts<span class="op">...&gt;</span>;</span>
<span id="cb26-69"><a href="#cb26-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-70"><a href="#cb26-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-71"><a href="#cb26-71" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>canonicalized<span class="op">&lt;</span>value_t<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;</span>, value_t<span class="op">&lt;-</span><span class="dv">1</span><span class="op">&gt;</span>, value_t<span class="op">&lt;-</span><span class="dv">1</span><span class="op">&gt;</span>, value_t<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;</span>, list<span class="op">&lt;</span>value_t<span class="op">&lt;-</span><span class="dv">1</span><span class="op">&gt;</span>, value_t<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;</span>, value_t<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;&gt;)</span>;</span></code></pre></div>
<h1 data-number="12" id="appendix-c-__pretty_function__-instability"><span class="header-section-number">12</span> Appendix C: <code class="sourceCode cpp"><span class="ot">__PRETTY_FUNCTION__</span></code>
instability<a href="#appendix-c-__pretty_function__-instability" class="self-link"></a></h1>
<p>This example is available at https://godbolt.org/z/ojb9TnE99 .</p>
<p>Consider the following program, contributed by Barry Revzin:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;print&gt;</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> E;</span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>E<span class="op">&gt;</span> <span class="kw">struct</span> C;</span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#ifdef DEFINED</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> E <span class="op">{</span> hi, gašper <span class="op">}</span>;</span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-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="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> show<span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, <span class="ot">__PRETTY_FUNCTION__</span><span class="op">)</span>;</span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a>    show<span class="op">&lt;</span>C<span class="op">&lt;</span>E<span class="op">(</span><span class="dv">0</span><span class="op">)&gt;&gt;()</span>;</span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>When compiled with <code class="sourceCode cpp"><span class="op">-</span>std<span class="op">=</span>c<span class="op">++</span><span class="dv">23</span></code>,
it yields the following output:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a>void show() [with T = C&lt;(E)0&gt;]</span></code></pre></div>
<p>However, with <code class="sourceCode cpp"><span class="op">-</span>std<span class="op">=</span>c<span class="op">++</span><span class="dv">23</span> <span class="op">-</span>DDEFINED</code>,
it produces a different one:</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a>void show() [with T = C&lt;E::hi&gt;]</span></code></pre></div>
<p>This makes external names of types incorporating enums as non-type
template arguments have inconsistent between translation units.</p>
<h1 data-number="13" id="appendix-d-proscons-slide-from-ewg-wroclaw"><span class="header-section-number">13</span> Appendix D: pros/cons slide from
EWG Wroclaw<a href="#appendix-d-proscons-slide-from-ewg-wroclaw" class="self-link"></a></h1>
<p>Implementation-defined or fully specified by the standard?</p>
<ul>
<li>Implementation defined:
<ul>
<li>Pro: ABIs already did all the work</li>
<li>Cons:
<ul>
<li>ABIs don’t agree</li>
<li>Frontend doesn’t know ABI for static analysis tools</li>
<li>Layering violation (Erich says that’s already happening)</li>
<li>Compilers need to agree to have compatible ABI</li>
<li>Not necessarily self-consistent (name mangling uses compression) -
Erich says it’s probably ok</li>
</ul></li>
</ul></li>
<li>Fully specified:
<ul>
<li>Pros:
<ul>
<li>Fully portable, including static analysis tools</li>
<li>Faster than mangling during constexpr evaluation (Erich says they
can short-circuit)</li>
<li>(comparison does not require stringifying long symbol names, it
short-circuits quickly)</li>
<li>Does not require the frontend to know the ABI (helps IDEs) (Erich
says not true)</li>
</ul></li>
<li>Cons:
<ul>
<li>Lots of work</li>
<li>Anonymous entities require a completely new-to-standard notion of a
“declaration scope” with all the template arguments of all enclosing
scopes</li>
<li>We need to continue to specify ordering for every change to language
entities</li>
</ul></li>
</ul></li>
</ul>
<h1 data-number="14" id="appendix-zzz-this-his-how-deep-the-rabbit-hole-goes"><span class="header-section-number">14</span> Appendix ZZZ: This his how deep
the rabbit hole goes<a href="#appendix-zzz-this-his-how-deep-the-rabbit-hole-goes" class="self-link"></a></h1>
<p>This section is left in the paper as a hint to the reader of how
horrible specifying all of this would be for the language, without
punting it to ABI specifications.</p>
<p>It is left here as the mess it was at the end of the attempt.</p>
<h2 data-number="14.1" id="foreword"><span class="header-section-number">14.1</span> Foreword<a href="#foreword" class="self-link"></a></h2>
<p>This section sets out an approach for defining an ordering of all
compile-time entities; that is, the definition of <code class="sourceCode cpp">SORT_KEY<span class="op">(</span>X<span class="op">)</span></code>
for a given <em>cv</em>-qualified type
<code class="sourceCode cpp">X</code>; and the comparison function
between these sort-key-tuples.</p>
<p><strong>Note to reviewers:</strong> <em>any</em> well-defined order
will satisfy the design requirements; the chief design element here is
whether we have achieved a well-ordering, not what exactly it is. The
only other considration is whether we can evolve the order as we
introduce new entities into the language.</p>
<h2 data-number="14.2" id="approach"><span class="header-section-number">14.2</span> Approach<a href="#approach" class="self-link"></a></h2>
<ol type="1">
<li>We define a <strong>lowering to a <em>sort-key-tuple</em></strong>
for every entity in the language.</li>
<li>The order is then defined on these <em>sort-key-tuples</em>.</li>
</ol>
<p>The entities we must order are:</p>
<ol type="1">
<li>namespaces and modules
<ol type="1">
<li>the global namespace</li>
<li>named namespaces</li>
<li>the anonymous namespace</li>
<li>modules</li>
</ol></li>
<li>cv-qualified types
<ol type="1">
<li>scalar types</li>
<li>array types</li>
<li>class and union types</li>
<li>class and union template specializations</li>
<li>anonymous versions of all of the above</li>
<li>function types</li>
</ol></li>
<li>templates
<ol type="1">
<li>function templates</li>
<li>class templates</li>
<li>variable templates</li>
<li>concepts</li>
<li>type alias templates</li>
<li>deduction guides</li>
</ol></li>
<li>partial template specializations
<ol type="1">
<li>partial function template specializations</li>
<li>partial class template specializations</li>
<li>partial variable template specializations</li>
</ol></li>
<li>parameters
<ol type="1">
<li>runtime-parameters</li>
<li>type-parameters</li>
<li>constant-parameters</li>
<li>type-template parameters</li>
<li>concept-parameters</li>
<li>variable-template parameters</li>
<li>parameter packs</li>
</ol></li>
<li>constants
<ol type="1">
<li>integral constants</li>
<li>floating-point constants</li>
<li>pointer and reference constants
<ol type="1">
<li>to functions</li>
<li>to named entities of static storage duration</li>
<li>to expressions</li>
</ol></li>
<li>class-type constants
<ol type="1">
<li>lambda literals</li>
<li>constants of compound types usable as template arguments</li>
</ol></li>
</ol></li>
<li>expressions</li>
</ol>
<h2 data-number="14.3" id="structure-of-sort-key-tuples"><span class="header-section-number">14.3</span> Structure of sort-key-tuples<a href="#structure-of-sort-key-tuples" class="self-link"></a></h2>
<p>Every <em>sort-key-tuple</em> is of the form <code class="sourceCode cpp"><span class="op">(</span><em>element</em><span class="op">...)</span></code>.</p>
<p>where an element is one of:</p>
<ul>
<li><em>atom</em> (see <a href="#atoms">atoms</a>)</li>
<li><em>name</em></li>
<li><em>constant</em></li>
<li><em>sort-key-tuple</em></li>
</ul>
<p>These tuples are then ordered lexicographically (ties broken in favor
of shorter tuple), atoms first, then names, then constants, then other
<em>sort-key-tuples</em>.</p>
<p>Let us name this transformation as <code class="sourceCode cpp">sort_key<span class="op">(</span>entity<span class="op">)</span></code>.</p>
<p>The rest of the design is concerned with defining this
transformation.</p>
<h2 data-number="14.4" id="decl-scopes"><span class="header-section-number">14.4</span> decl-scopes<a href="#decl-scopes" class="self-link"></a></h2>
<p>A sort-key for most entities is of the form</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>sort_key(x) = (sort_key(decl-scope(x)), x-dependent-elements...)</span></code></pre></div>
<p>This section deals with the decl-scope of an entity.</p>
<p>To deal with anonymous types and templated entities like hidden
friends, we have to observe more than just the namespace and class the
entity is declared in; we must also observe anything at all that could
contribute to the declaration, such as template parameters and arguments
of partial and full template specializations of both class and function
templates, alias templates, concepts, their parameter numbers (in case
of default arguments), and so on. After that, we must make special
allowances for entities that cannot be influenced by such surroundings,
such as forward declaratios of named classes.</p>
<h3 data-number="14.4.1" id="every-declaration-introduces-a-decl-scope."><span class="header-section-number">14.4.1</span> Every declaration introduces
a decl-scope.<a href="#every-declaration-introduces-a-decl-scope." class="self-link"></a></h3>
<ul>
<li>Every declaration <em>of an anonymous entity</em> is ordered
lexicographically within its decl-scope.</li>
<li>Ties are not broken; there should be no conflicts, as all the
context for a given <em>sort-key(x)</em> should be provided by the
decl-scope of the declaration. (notably - all relevant parameters
<em>and</em> their values should be part of the sort-key for a given
declaration of an anonymous entity)</li>
<li>Named entities’ decl-scope is their normal declaration scope.</li>
</ul>
<h2 data-number="14.5" id="what-to-do-with-undefined-comparisons"><span class="header-section-number">14.5</span> What to do with undefined
comparisons?<a href="#what-to-do-with-undefined-comparisons" class="self-link"></a></h2>
<p>Some comparisons could be left to future revisions because of
omissions or incomplete work. If a program /observes/ such a comparison,
the program should be ill-formed (diagnostic required).</p>
<p>This is to enable fixing the issue in a future revision of the
standard. It is the intention of the authors of this paper that such
comparisons should be exceedingly difficult to observe in practice in
normal code, since most comparisons should be tie-broken fairly early
on.</p>
<h2 data-number="14.6" id="modules"><span class="header-section-number">14.6</span> Modules<a href="#modules" class="self-link"></a></h2>
<p>Every entity that belongs to a module has that module’s full name as
a string as the first part of its
<code class="sourceCode cpp">sort_scope</code>. If an entity belongs to
the global module, it has the atom <em>global-module</em> as its
name.</p>
<h2 data-number="14.7" id="namespaces"><span class="header-section-number">14.7</span> Namespaces<a href="#namespaces" class="self-link"></a></h2>
<p>This section deals with namespaces and their sort-keys.</p>
<h3 data-number="14.7.1" id="the-global-namespace"><span class="header-section-number">14.7.1</span> The global namespace<a href="#the-global-namespace" class="self-link"></a></h3>
<p>Let <em>x</em> be the global namespace.</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a>sort_scope(x) := ()</span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>sort_key(x) := (sort_scope(x), _namespace_, _global-namespace_)</span></code></pre></div>
<h3 data-number="14.7.2" id="named-namespaces"><span class="header-section-number">14.7.2</span> Named namespaces<a href="#named-namespaces" class="self-link"></a></h3>
<p>Every namespace (except for the global namespace) has a parent
namespace, which is its immediately enclosing namespace.</p>
<p>let <em>x</em> be some named namespace with the simple-name
“namespace_name”.</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a>sort_scope(x) := sort_key(parent_namespace)</span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>sort_key(x) := (sort_scope(x), _namespace_, &quot;namespace_name&quot;)</span></code></pre></div>
<h3 data-number="14.7.3" id="the-anonymous-namespace"><span class="header-section-number">14.7.3</span> The anonymous namespace<a href="#the-anonymous-namespace" class="self-link"></a></h3>
<p>The anonymous namespace sorts after all the other namespaces.</p>
<p>Let <em>x</em> be some anonymous namespace, with parent namespace
<code class="sourceCode cpp">parent_namespace</code>.</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a>sort_scope(x) := sort_key(parent_namespace)</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>sort_key(x) := (sort_scope(x), _namespace_, _anonymous_)</span></code></pre></div>
<p>This is ok, as there is only one anonymous namespace per namespace
per compilation unit.</p>
<h3 data-number="14.7.4" id="namespace-examples"><span class="header-section-number">14.7.4</span> Namespace examples<a href="#namespace-examples" class="self-link"></a></h3>
<div class="sourceCode" id="cb34"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>sort_key(::std::ranges) = (</span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>    (</span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a>        ((), _namespace_, _global-namespace_), // sort_key(global-namespace)</span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a>        _namespace_, &quot;std&quot;</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>    ), // sort_key(::std)</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>    _namespace_, &quot;ranges&quot;</span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a>);</span></code></pre></div>
<h2 data-number="14.8" id="cv-qualified-types"><span class="header-section-number">14.8</span> cv-qualified types<a href="#cv-qualified-types" class="self-link"></a></h2>
<h3 data-number="14.8.1" id="qualifiers"><span class="header-section-number">14.8.1</span> Qualifiers<a href="#qualifiers" class="self-link"></a></h3>
<p>Qualifiers are each assigned a score</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a>&amp;: 1</span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>&amp;&amp;: 2</span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>const: 3</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>volatile: 6</span></code></pre></div>
<p>and ordering lowest-first after summing them.</p>
<p>Any implementation-defined qualifiers get a score that is 2x the
largest score in the table; for instance
<code class="sourceCode cpp"><span class="ex">__restrict</span></code>
gets <code class="sourceCode cpp"><span class="dv">12</span></code>.</p>
<p>Therefore, for an unqualified type
<code class="sourceCode cpp">T</code>, the order of all possible
qualified types would be:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span>  T</span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span>  T <span class="op">&amp;</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span>  T <span class="op">&amp;&amp;</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span>  T <span class="kw">const</span></span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a><span class="dv">4</span>  T <span class="kw">const</span> <span class="op">&amp;</span></span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span>  T <span class="kw">const</span> <span class="op">&amp;&amp;</span></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span>  T <span class="kw">volatile</span></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span>  T <span class="kw">volatile</span> <span class="op">&amp;</span></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a><span class="dv">8</span>  T <span class="kw">volatile</span> <span class="op">&amp;&amp;</span></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a><span class="dv">9</span>  T <span class="kw">const</span> <span class="kw">volatile</span></span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a><span class="dv">10</span> T <span class="kw">const</span> <span class="kw">volatile</span> <span class="op">&amp;</span></span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a><span class="dv">11</span> T <span class="kw">const</span> <span class="kw">volatile</span> <span class="op">&amp;&amp;</span></span></code></pre></div>
<p>This is accomplished by putting the qualifier sequence into the tuple
just after the typename.</p>
<p>For a given type <code class="sourceCode cpp">T</code>, we define</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>qualifier_sequence(T const volatile &amp;) := const volatile &amp;</span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>qualifier_sequence(T const volatile &amp;&amp;) := const volatile &amp;&amp;</span></code></pre></div>
<p>so that we can put it into the
<code class="sourceCode cpp">sort_key</code> tuple later.</p>
<h3 data-number="14.8.2" id="scalar-types"><span class="header-section-number">14.8.2</span> Scalar Types<a href="#scalar-types" class="self-link"></a></h3>
<p>All scalar types are built-in types, except for user-defined
enumerations, which should be ordered as if they were class types.</p>
<p>Simple scalar types (everything in this section but function types
and pointer types) are not ordered by “name” - they are ordered using
the rules in the table. All atoms are still ordered before them, any
name is ordered after them, as are all sort-key-tuples.</p>
<p>This is because some of the built-in types do not have names, only
type aliases (such as <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(</span><span class="kw">nullptr</span><span class="op">)</span></code>),
and we do not order types by their aliases.</p>
<p>This causes any built-in scalar types to be ordered before any
compound types.</p>
<p>In case of ties, built-in types with simple names shall be ordered
before any nameless types.</p>
<p>In particular, scalar types shall be ordered as follows:</p>
<ol type="1">
<li><code class="sourceCode cpp"><span class="dt">void</span></code>
comes first because it’s not reifiable,</li>
<li>the type of <code class="sourceCode cpp">std<span class="op">::</span>nullptr_t</code> as
the first monostate</li>
<li>any other monostates, if added, sorted alphabetically by their
common names (to be specified explicitly if added)</li>
<li><code class="sourceCode cpp"><span class="dt">bool</span></code> as
the first bi-state</li>
<li>any other bi-states, if added, sorted alphabetically.</li>
<li>Raw-memory types
(<code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp"><span class="dt">signed</span> <span class="dt">char</span></code>,
<code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>)
(std::byte is an enumeration in <code class="sourceCode cpp">std</code>
so it falls under different rules)</li>
<li>Integral types in order of size, signed before unsigned
(<code class="sourceCode cpp"><span class="dt">short</span></code>,
<code class="sourceCode cpp"><span class="dt">unsigned</span>    <span class="dt">short</span></code>,
<code class="sourceCode cpp"><span class="dt">int</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">int</span></code>,
<code class="sourceCode cpp"><span class="dt">long</span></code>, <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">long</span></code>,
<code class="sourceCode cpp"><span class="dt">long</span> <span class="dt">long</span></code>,
<code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">long</span> <span class="dt">long</span></code>,
followed by any implementation-defined wider integral types like
<code class="sourceCode cpp">__int128_t</code> etc.). Intersperse any
implementation-defined built-in integral types as needed between the
above following those rules.</li>
<li>Any remaining character types that are not type-aliases of any of
the above, including unicode, according to the following rules: smallest
first, unicode-specific variants after non-unicode variants.</li>
<li>Floating-point types, in order of size. In case of ties,
<code class="sourceCode cpp"><span class="dt">float</span></code>,
<code class="sourceCode cpp"><span class="dt">double</span></code> and
<code class="sourceCode cpp"><span class="dt">long</span> <span class="dt">double</span></code>
come before any other floating point types of the same size. Any
decimal-floating-point types come after binary-floating-point types; if
multiple floating point types of the same bit-length exist, break ties
by the bit-size of the exponent, lower first.</li>
<li>Implementation-defined vector-register types, ordered by the the
integral type they consist of, and then by bit-size (example:
<code class="sourceCode cpp">u8x16</code> from gcc’s
documentation).</li>
<li>Function types (internally ordered by rules in section <a href="#function-types">Function Types</a>)</li>
<li>Pointer types (internally ordered by their pointee-type)</li>
<li>Pointer-to-member types (internally ordered by pointee-type)</li>
</ol>
<h3 data-number="14.8.3" id="array-types"><span class="header-section-number">14.8.3</span> Array Types<a href="#array-types" class="self-link"></a></h3>
<p>TODO: this section is not complete.</p>
<p>Array types shall be ordered after scalar types but before class
types.</p>
<p>Given a non-array type <code class="sourceCode cpp">T</code></p>
<div class="sourceCode" id="cb38"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a>sort_key(T[])  := (sort_key(T), [])</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>sort_key(T[n]) := (sort_key(T), [], n)</span></code></pre></div>
<p>Multidimensional arrays, as an example:</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a>sort_key(int[][n]) = (sort_key(int[]), [], n) = ((sort_key(int), []), [], n);</span></code></pre></div>
<p>Notice:</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a>sort_key(int[]) &lt; sort_key(int[2])</span></code></pre></div>
<p>because the shorter tuple wins a tie.</p>
<h3 data-number="14.8.4" id="expressions"><span class="header-section-number">14.8.4</span> Expressions<a href="#expressions" class="self-link"></a></h3>
<p>Example (courtesy of Lénárd Szolnoki)</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a>template &lt;auto x&gt;</span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a>struct S {};</span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a>template &lt;int x&gt;</span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a>void foo(S&lt;2*x&gt;) {}</span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a>inline constexpr auto a = &amp;foo&lt;0&gt;;</span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a>template &lt;int x&gt;</span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a>void foo(S&lt;x&gt;) {}</span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a>inline constexpr void (*b)(S&lt;0&gt;) = &amp;foo;</span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a>inline constexpr auto x = TYPE-ORDER(S&lt;x&gt;, S&lt;y&gt;); // not equal</span></code></pre></div>
<p>We must therefore sort arbitrary expressions; I propose we avoid that
by making such comparisons, should they occur, ill-formed, until we are
forced to define them.</p>
<h3 data-number="14.8.5" id="lambdas"><span class="header-section-number">14.8.5</span> Lambdas<a href="#lambdas" class="self-link"></a></h3>
<p>A lambda type is an anonymous type, which means it’s
lexicographically numbered within its
<code class="sourceCode cpp">sort_scope</code>.</p>
<p>Example:</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a>template &lt;auto T&gt; C {};</span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a>static_assert(type_order_v&lt;</span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a>        C&lt;[]{}&gt;, // lambda-key: (sort_key(static_assert), _type_, _anonymous_, 1)</span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a>        C&lt;[]{}&gt;  // lambda-key: (sort_key(static_assert), _type_, _anonymous_, 2)</span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a>    &gt;</span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a>    == std::strong_order::less);</span></code></pre></div>
<p>TODO: port stuff from bottom.</p>
<h2 data-number="14.9" id="old-design-that-needs-to-be-revamped"><span class="header-section-number">14.9</span> Old design that needs to be
revamped<a href="#old-design-that-needs-to-be-revamped" class="self-link"></a></h2>
<h3 data-number="14.9.1" id="example-1-class-foo-is-declared-in-struct-bar"><span class="header-section-number">14.9.1</span> Example 1:
<code class="sourceCode cpp"><span class="kw">class</span> foo</code> is
declared in
<code class="sourceCode cpp"><span class="kw">struct</span> bar</code>:<a href="#example-1-class-foo-is-declared-in-struct-bar" class="self-link"></a></h3>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> bar <span class="op">{</span> <span class="kw">class</span> foo; <span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb44"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a>sort_key(foo) = (sort_key(bar), sort_key(foo)) = ((type, bar), (type, foo, ))</span></code></pre></div>
<p>This shall hold for any of the above named scopes.</p>
<h3 data-number="14.9.2" id="example"><span class="header-section-number">14.9.2</span> Example:<a href="#example" class="self-link"></a></h3>
<p>Given</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> foo<span class="op">::</span>bar <span class="op">{</span></span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> baz <span class="op">{</span></span>
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> j;</span>
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Then:</p>
<ul>
<li><code class="sourceCode cpp">sort_key<span class="op">(</span>foo<span class="op">::</span>bar<span class="op">::</span>i<span class="op">)</span></code>
is <code class="sourceCode cpp"><span class="op">((</span><span class="kw">namespace</span>, foo<span class="op">)</span>, <span class="op">(</span><span class="kw">namespace</span>, bar<span class="op">)</span>, <span class="op">(</span>type, i, <span class="op">))</span></code>.</li>
<li><code class="sourceCode cpp">sort_key<span class="op">(</span>baz<span class="op">::</span>j<span class="op">)</span></code>
is <code class="sourceCode cpp"><span class="op">((</span><span class="kw">namespace</span>, baz<span class="op">)</span>, <span class="op">(</span>type, j, <span class="op">))</span></code></li>
</ul>
<p>When compared, the result is that
<code class="sourceCode cpp">baz<span class="op">::</span>j</code> &lt;
<code class="sourceCode cpp">foo<span class="op">::</span>bar<span class="op">::</span>i</code>,
since <code class="sourceCode cpp"><span class="kw">namespace</span> baz</code>
precedes <code class="sourceCode cpp"><span class="kw">namespace</span> foo</code>.</p>
<h2 data-number="14.10" id="atoms"><span class="header-section-number">14.10</span> Atoms<a href="#atoms" class="self-link"></a></h2>
<p>The atoms of <em>key-tuples</em> are ordered as follows:</p>
<ol type="1">
<li><em>global-module</em></li>
<li><em>global-namespace</em></li>
<li><em>anonymous</em></li>
<li>kinds (see <a href="#kinds">kinds</a>)</li>
<li>qualifiers (see <a href="#qualifiers">qualifiers</a>)</li>
<li><code class="sourceCode cpp"><span class="op">[]</span></code>
(array of unknown bound)</li>
<li><code class="sourceCode cpp"><span class="op">*</span></code>
(pointer)</li>
<li>ellipsis
(<code class="sourceCode cpp"><span class="op">...</span></code> in
<code class="sourceCode cpp">f<span class="op">(...)</span></code>)</li>
<li>parameter pack
(<code class="sourceCode cpp"><span class="op">...</span></code> in
<code class="sourceCode cpp"><span class="kw">typename</span><span class="op">...</span></code>)</li>
<li>template parameter <em>auto</em></li>
<li>template parameter <em>typename</em></li>
<li>template parameter T</li>
</ol>
<h2 data-number="14.11" id="identifiers"><span class="header-section-number">14.11</span> identifiers<a href="#identifiers" class="self-link"></a></h2>
<p>These are simple names (identifiers).</p>
<p>Examples: “pair”, “string”, “unique_ptr”, “std”, “hashmap”,
“absl”.</p>
<h2 data-number="14.12" id="kinds"><span class="header-section-number">14.12</span> Kinds<a href="#kinds" class="self-link"></a></h2>
<p>There are the following kind tokens that can appear in
<em>key-tuples</em>.</p>
<ol type="1">
<li>value</li>
<li>namespace</li>
<li>type</li>
<li>class template</li>
<li>type alias template</li>
<li>variable template</li>
<li>concept</li>
<li>function</li>
</ol>
<p>Note: everything but “values” is pretty simple, but we haven’t dealt
with values extensively yet with the R1 of this paper, though we should
just defer to
<code class="sourceCode cpp"><span class="op">&lt;=&gt;</span></code>
and require a default strong structural ordering for values that may be
template arguments.</p>
<h3 data-number="14.12.1" id="identifiers-1"><span class="header-section-number">14.12.1</span> Identifiers<a href="#identifiers-1" class="self-link"></a></h3>
<h4 data-number="14.12.1.1" id="simple-names"><span class="header-section-number">14.12.1.1</span> Simple Names<a href="#simple-names" class="self-link"></a></h4>
<p>Most names are strings that are valid (atomic) identifiers. Those are
just themselves:</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> foo<span class="op">::</span>bar <span class="op">{</span> <span class="kw">struct</span> baz; <span class="op">}</span></span></code></pre></div>
<p><code class="sourceCode cpp">foo</code>,
<code class="sourceCode cpp">bar</code> and
<code class="sourceCode cpp">baz</code> are such atomic identifiers.</p>
<h4 data-number="14.12.1.2" id="unnamed-entities"><span class="header-section-number">14.12.1.2</span> Unnamed entities<a href="#unnamed-entities" class="self-link"></a></h4>
<p>Unnamed entities are all assigned a key-tuple of their decl-scope and
then numbered lexically, consecutively, starting with zero, with the
counter being scoped to their decl-scope.</p>
<h5 data-number="14.12.1.2.1" id="decl-scopes-1"><span class="header-section-number">14.12.1.2.1</span> Decl-scopes<a href="#decl-scopes-1" class="self-link"></a></h5>
<p>Decl-scopes are:</p>
<ul>
<li>namespaces</li>
<li>class definitions</li>
<li>union definitions</li>
<li>function declarations</li>
<li>function default argument definitions</li>
<li>function definitions</li>
<li>enumeration definitions</li>
<li>type aliases</li>
<li>pack expansions</li>
<li>template parameter declarations</li>
<li>definitions of template argument defaults</li>
<li>class template declarations</li>
<li>class template definitions</li>
<li>definitions of partial class template specializations</li>
<li>definitions of class template specializations</li>
<li>function template declarations</li>
<li>function template definitions</li>
<li>function template default argument definitions</li>
<li>type alias templates</li>
<li>concept definitions</li>
<li>default initializers for class members</li>
</ul>
<h5 data-number="14.12.1.2.2" id="examples"><span class="header-section-number">14.12.1.2.2</span> Examples<a href="#examples" class="self-link"></a></h5>
<p>Function declarations are scoped to the function itself.</p>
<p>Consider a lambda that appears as a default argument of a function
template:</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-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="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">(</span>T x <span class="op">=</span> <span class="op">[]{</span> <span class="cf">return</span> T<span class="op">{</span><span class="dv">0</span><span class="op">}</span>; <span class="op">}())</span>;</span>
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a><span class="co">//           ^^^^^^^^^^^^^^^^^^ this one</span></span></code></pre></div>
<p>The <em>key-tuple</em> for <code class="sourceCode cpp">f<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>
is:</p>
<p><code class="sourceCode cpp"><span class="op">(</span>function, <span class="op">(</span>f, <span class="op">(</span>type, <span class="dt">int</span><span class="op">))</span>, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span><span class="op">)))</span></code></p>
<p>The <em>key-tuple</em> for the lambda is:</p>
<p><code class="sourceCode cpp"><span class="op">((</span>function, <span class="op">(</span>f, <span class="op">(</span>type, <span class="dt">int</span><span class="op">))</span>, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span><span class="op">)))</span>, <span class="op">(</span>type, <span class="op">(</span>lambda, <span class="dv">0</span><span class="op">)</span>, <span class="op">))</span></code>.</p>
<p>Note: because of the regular structure of <em>key-tuples</em>, such
anonymous classes will compare greater than any entity that has a simple
identifier, due to tuples comparing greater than atoms (which simple
names are).</p>
<h5 data-number="14.12.1.2.3" id="lambda-types"><span class="header-section-number">14.12.1.2.3</span> Lambda types<a href="#lambda-types" class="self-link"></a></h5>
<p>As unnamed entities - the types of lambdas are ordered first by where
they are declared, then by declaration (lexical) order.</p>
<p>In effect, we assign them the name <code class="sourceCode cpp"><span class="op">(</span>lambda, <span class="er">#)</span></code>
where <code class="sourceCode cpp"><span class="er">#</span></code> is
the count of other unnamed entities in the decl-scope.</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> Banana <span class="op">{</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">auto</span> i <span class="op">=</span> <span class="op">[](</span><span class="dt">int</span><span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{}</span>; <span class="co">// 0th lambda instantiated in Banana</span></span>
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> Apple <span class="op">{</span></span>
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> i <span class="op">=</span> <span class="op">[](</span><span class="dt">float</span><span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{}</span>; <span class="co">// 0th lambda instantiated in Apple</span></span>
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> j <span class="op">=</span> <span class="op">[]()</span> <span class="op">-&gt;</span> std<span class="op">::</span>string <span class="op">{}</span>; <span class="co">// 1st lambda instantiated in Apple</span></span>
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>These would produce the following tuples:</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a>sort_key(decltype(Banana::i)) = ((namespace, Banana), (type, (lambda, 0), ));</span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>sort_key(decltype(Apple::i))  = ((namespace, Apple), (type, (lambda, 0), ));</span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a>sort_key(decltype(Apple::j))  = ((namespace, Apple), (type, (lambda, 1), ));</span></code></pre></div>
<p>Note: the empty bit after the identifier is the empty qualifier
pack.</p>
<h5 data-number="14.12.1.2.4" id="unnamed-struct-and-union-types"><span class="header-section-number">14.12.1.2.4</span> Unnamed
<code class="sourceCode cpp"><span class="kw">struct</span></code> and
<code class="sourceCode cpp"><span class="kw">union</span></code>
types<a href="#unnamed-struct-and-union-types" class="self-link"></a></h5>
<p>They are named, respectively, <code class="sourceCode cpp"><span class="op">(</span><span class="kw">class</span>, <span class="er">#)</span></code>
and <code class="sourceCode cpp"><span class="op">(</span><span class="kw">union</span>, <span class="er">#)</span></code>.</p>
<p><strong>Example:</strong> in a type alias like <code class="sourceCode cpp"><span class="kw">typedef</span> <span class="kw">struct</span> <span class="op">{}</span> S;</code>,
the unnamed struct type is decl-scoped to the alias declaration
<code class="sourceCode cpp">S</code>.</p>
<h3 data-number="14.12.2" id="namespaces-1"><span class="header-section-number">14.12.2</span> Namespaces<a href="#namespaces-1" class="self-link"></a></h3>
<p>The <code class="sourceCode cpp">sort_key<span class="op">(</span><span class="kw">namespace</span><span class="op">-</span>name<span class="op">)</span></code>
is <code class="sourceCode cpp"><span class="op">(</span><span class="kw">namespace</span>, identifier<span class="op">)</span></code>.</p>
<p>This means that namespaces are ordered alphabetically by comparing
namespace names at the same rank. A namespace comes before any of its
subnamespaces.</p>
<p>Example:</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> outer1 <span class="op">{</span></span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> i;</span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> outer2 <span class="op">{</span></span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">namespace</span> inner1 <span class="op">{</span></span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb50-9"><a href="#cb50-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">namespace</span> inner2 <span class="op">{</span></span>
<span id="cb50-10"><a href="#cb50-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb50-11"><a href="#cb50-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb50-12"><a href="#cb50-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The order of the three structs w/ type
<code class="sourceCode cpp">i</code> types shall be</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>outer1<span class="op">::</span>i<span class="op">)</span> <span class="op">&lt;</span> sort_key<span class="op">(</span>outer2<span class="op">::</span>inner1<span class="op">::</span>i<span class="op">)</span> <span class="op">&lt;</span> sort_key<span class="op">(</span>outer2<span class="op">::</span>inner2<span class="op">::</span>i<span class="op">)</span></code>.</p>
<h3 data-number="14.12.3" id="types"><span class="header-section-number">14.12.3</span> Types<a href="#types" class="self-link"></a></h3>
<p>The <code class="sourceCode cpp">sort_key</code> of a type is <code class="sourceCode cpp"><span class="op">(</span>type, <span class="op">&lt;</span>identifier<span class="op">&gt;</span>, <span class="op">&lt;</span>qualifiers<span class="op">&gt;)</span></code>.</p>
<p>The <code class="sourceCode cpp"><span class="op">&lt;</span>identifier<span class="op">&gt;</span></code>
bit is a bit complicated, so let’s deal with the qualifiers first.</p>
<p>Note: any decl-scopes the <code class="sourceCode cpp">type</code> is
declared in are part of the parent <em>key-tuple</em>. The
<code class="sourceCode cpp">identifier</code> portion is complicated
because of possible template arguments for types that are template
specializations.</p>
<h3 data-number="14.12.4" id="ordering-class-types"><span class="header-section-number">14.12.4</span> Ordering Class Types<a href="#ordering-class-types" class="self-link"></a></h3>
<h4 data-number="14.12.4.1" id="ordering-simple-class-types"><span class="header-section-number">14.12.4.1</span> Ordering Simple Class
Types<a href="#ordering-simple-class-types" class="self-link"></a></h4>
<p>Class types shall be greater than scalar types.</p>
<p>Since we cannot redeclare two types with the same name, class types
shall be ordered alphabetically.</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Apple <span class="op">{}</span>;</span>
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Banana <span class="op">{}</span>;</span>
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Carrot <span class="op">{}</span>;</span></code></pre></div>
<p>Would be ordered as <code class="sourceCode cpp">Apple <span class="op">&lt;</span> Banana <span class="op">&lt;</span> Carrot</code></p>
<p>As such, we define sort key as:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">)</span> <span class="op">=</span> <span class="op">(</span>type, Apple, <span class="op">)</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Banana<span class="op">)</span> <span class="op">=</span> <span class="op">(</span>type, Banana, <span class="op">)</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Carrot<span class="op">)</span> <span class="op">=</span> <span class="op">(</span>type, Carrot, <span class="op">)</span></code></p>
<h4 data-number="14.12.4.2" id="non-type-template-parameters"><span class="header-section-number">14.12.4.2</span> Non Type Template
Parameters<a href="#non-type-template-parameters" class="self-link"></a></h4>
<p>NTTPs shall first be ordered by their type, then their value.</p>
<p>Given:</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> T<span class="op">&gt;</span></span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> s <span class="op">{</span></span>
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">decltype</span><span class="op">(</span>T<span class="op">)</span> i <span class="op">=</span> T;</span>
<span id="cb52-4"><a href="#cb52-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb52-5"><a href="#cb52-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb52-6"><a href="#cb52-6" aria-hidden="true" tabindex="-1"></a>s<span class="op">&lt;</span><span class="dv">1</span><span class="bu">u</span><span class="op">&gt;</span> a;</span>
<span id="cb52-7"><a href="#cb52-7" aria-hidden="true" tabindex="-1"></a>s<span class="op">&lt;</span><span class="fl">1.0</span><span class="bu">f</span><span class="op">&gt;</span> b;</span></code></pre></div>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>s<span class="op">&lt;</span><span class="dv">1</span><span class="bu">u</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">((</span>type, <span class="op">(</span>s, sort_key<span class="op">(</span><span class="dv">1</span><span class="bu">u</span><span class="op">))))</span></code></p>
<p>We can define sort_key of <code class="sourceCode cpp"><span class="dv">1</span><span class="bu">u</span></code>
as: <code class="sourceCode cpp">sort_key<span class="op">(</span><span class="dv">1</span><span class="bu">u</span><span class="op">)</span> <span class="op">=</span> <span class="op">(</span> sort_key<span class="op">(</span><span class="kw">decltype</span><span class="op">(</span><span class="dv">1</span><span class="bu">u</span><span class="op">))</span>, <span class="dv">1</span><span class="op">)</span></code></p>
<p><code class="sourceCode cpp">s<span class="op">&lt;</span><span class="dv">1</span><span class="bu">u</span><span class="op">&gt;</span></code>
shall be ordered before <code class="sourceCode cpp">s<span class="op">&lt;</span><span class="fl">1.0</span><span class="bu">f</span><span class="op">&gt;</span></code>,
as integral types come before floating point types.</p>
<p>NTTPs of the same type shall be lexicographically ordered by their
scalar subobjects. Meaning</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> F <span class="kw">final</span> <span class="op">{</span></span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> G <span class="kw">final</span> <span class="op">{</span></span>
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> h;</span>
<span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> i;</span>
<span id="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> g;</span>
<span id="cb53-6"><a href="#cb53-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> j;</span>
<span id="cb53-7"><a href="#cb53-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb53-8"><a href="#cb53-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb53-9"><a href="#cb53-9" aria-hidden="true" tabindex="-1"></a>F f<span class="op">{{</span><span class="dv">0</span>,<span class="dv">1</span><span class="op">}</span>, <span class="dv">2</span><span class="op">}</span>;</span>
<span id="cb53-10"><a href="#cb53-10" aria-hidden="true" tabindex="-1"></a>F f2<span class="op">{{</span><span class="dv">1</span>,<span class="dv">2</span><span class="op">}</span>, <span class="dv">3</span><span class="op">}</span>;</span></code></pre></div>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>s<span class="op">&lt;</span>f<span class="op">&gt;)</span> <span class="op">&lt;</span> sort_key<span class="op">(</span>s<span class="op">&lt;</span>f2<span class="op">&gt;)</span></code>;</p>
<p>NTTPs of the same pointer or reference type shall be ordered by
instantiation order.</p>
<h4 data-number="14.12.4.3" id="ordering-class-template-specializations"><span class="header-section-number">14.12.4.3</span> Ordering Class Template
Specializations<a href="#ordering-class-template-specializations" class="self-link"></a></h4>
<p>Class templates shall be ordered by:</p>
<ol type="1">
<li>Class name, alphabetically.</li>
<li>Template arguments, applied lexicographically.</li>
</ol>
<p>For example, given:</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> U<span class="op">&gt;</span></span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Apple;</span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Banana;</span>
<span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Carrot;</span>
<span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a>Apple<span class="op">&lt;</span>Banana, Carrot<span class="op">&gt;</span>;</span>
<span id="cb54-8"><a href="#cb54-8" aria-hidden="true" tabindex="-1"></a>Apple<span class="op">&lt;</span>Banana, Banana<span class="op">&gt;</span>;</span>
<span id="cb54-9"><a href="#cb54-9" aria-hidden="true" tabindex="-1"></a>Apple<span class="op">&lt;</span>Carrot, Carrot<span class="op">&gt;</span>;</span></code></pre></div>
<p>Note, <code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>parameter<span class="op">&gt;)...</span></code>
will be used to denote a tuple where
<code class="sourceCode cpp">sort_key</code> has been applied to all
parameters.</p>
<p>For <code class="sourceCode cpp"><span class="dt">void</span> f<span class="op">(</span>Foo, Bar<span class="op">)</span></code>
<code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>parameter<span class="op">&gt;)...</span></code>
would mean <code class="sourceCode cpp"><span class="op">(</span>sort_key<span class="op">(</span>Foo<span class="op">)</span>, sort_key<span class="op">(</span>Bar<span class="op">))</span></code></p>
<p><code class="sourceCode cpp">sort_key</code> of a class template
shall be defined as:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span><span class="kw">class</span> <span class="kw">template</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(&lt;</span>name<span class="op">&gt;</span>, <span class="op">(</span>sort_key<span class="op">(&lt;</span>parameter<span class="op">&gt;)...)))</span></code></p>
<p>So</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">&lt;</span>Banana, Carrot<span class="op">&gt;</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(</span>Apple, <span class="op">(</span>sort_key<span class="op">(</span>Banana<span class="op">)</span>, sort_key<span class="op">(</span>Carrot<span class="op">))</span>, <span class="op">)</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">&lt;</span>Banana, Carrot<span class="op">&gt;</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(</span>Apple, <span class="op">((</span>type, Banana, <span class="op">)</span>, <span class="op">(</span>type, Carrot, <span class="op">))</span>, <span class="op">)</span></code></p>
<p>Note: the empty bit after the identifier is the empty qualifier
pack.</p>
<p>The above would be ordered <code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">&lt;</span>Banana, Banana<span class="op">&gt;)</span></code>,
<code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">&lt;</span>Banana, Carrot<span class="op">&gt;)</span></code>,
<code class="sourceCode cpp">sort_key<span class="op">(</span>Apple<span class="op">&lt;</span>Carrot, Carrot<span class="op">&gt;</span></code>.</p>
<h4 data-number="14.12.4.4" id="function-types"><span class="header-section-number">14.12.4.4</span> Function Types<a href="#function-types" class="self-link"></a></h4>
<p>Function types shall be ordered by</p>
<ol type="1">
<li>Parameters, lexicographically.</li>
<li>Return type, if known from the declaration.</li>
</ol>
<p>The <code class="sourceCode cpp">sort_key</code> of a function shall
be defined as:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>function<span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>function, <span class="op">&lt;</span>name<span class="op">&gt;</span>, <span class="op">(</span>sort_key<span class="op">(&lt;</span>parameter<span class="op">&gt;)...)</span>, sort_key<span class="op">(&lt;</span><span class="cf">return</span> type<span class="op">&gt;))</span></code></p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span>;</span></code></pre></div>
<p>This function can be represented by: <code class="sourceCode cpp"><span class="op">(</span>function, <span class="op">(</span>foo, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span><span class="op">))))</span></code></p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span><span class="op">)</span></span>
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span>, <span class="dt">double</span><span class="op">)</span></span></code></pre></div>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span><span class="op">))</span> <span class="op">=</span> <span class="op">(</span>function, foo, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span><span class="op">)))</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span>, <span class="dt">double</span><span class="op">))</span> <span class="op">=</span> <span class="op">(</span>function, foo, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span><span class="op">)</span>, <span class="op">(</span>type, <span class="dt">double</span><span class="op">)))</span></code></p>
<p>So, the type of <code class="sourceCode cpp"><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span><span class="op">)</span></code>
would precede the type of <code class="sourceCode cpp"><span class="dt">void</span> foo<span class="op">(</span><span class="dt">int</span>, <span class="dt">double</span><span class="op">)</span></code></p>
<h4 data-number="14.12.4.5" id="member-function-types"><span class="header-section-number">14.12.4.5</span> Member Function Types<a href="#member-function-types" class="self-link"></a></h4>
<p>Function types shall be ordered by</p>
<ol type="1">
<li>Return type</li>
<li>The type of the class it is a member of.</li>
<li>Parameters, lexicographically.</li>
</ol>
<p>The sort key of a member function shall be defined as:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>member function<span class="op">&gt;)</span> <span class="op">=</span></code></p>
<p><code class="sourceCode cpp"><span class="op">(</span>function, <span class="op">(&lt;</span>name<span class="op">&gt;</span>, sort_key<span class="op">(&lt;</span><span class="kw">class</span><span class="op">&gt;))</span>, sort_key<span class="op">(&lt;</span><span class="cf">return</span> type<span class="op">&gt;)</span>, <span class="op">(</span>sort_key<span class="op">(&lt;</span>parameter<span class="op">&gt;)...))))</span></code></p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Foo <span class="op">{</span></span>
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> bar<span class="op">(</span><span class="dt">int</span> i, <span class="dt">float</span> j<span class="op">)</span>;</span>
<span id="cb57-3"><a href="#cb57-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>Foo<span class="op">::</span>bar<span class="op">)</span> <span class="op">=</span></code></p>
<p><code class="sourceCode cpp"><span class="op">(</span>type, Foo, <span class="op">)</span>, <span class="op">(</span>function, <span class="op">(</span>bar, <span class="op">(</span>type, Foo, <span class="op">))</span>, <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span>, <span class="op">((</span>type, <span class="dt">int</span>, <span class="op">)</span>, <span class="op">(</span>type, <span class="dt">float</span>, <span class="op">))))</span></code></p>
<h4 data-number="14.12.4.6" id="variadic-function-types"><span class="header-section-number">14.12.4.6</span> Variadic Function Types<a href="#variadic-function-types" class="self-link"></a></h4>
<p>Variadic function shall be ordered in a similar way. In a variadic
function, the last argument is a variadic argument. A variadic argument
shall be ordered immediately after its underlying type.</p>
<p>Given:</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>Foo<span class="op">)</span>;</span>
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>Foo<span class="op">...)</span>;</span></code></pre></div>
<p>In this case, the type of <code class="sourceCode cpp"><span class="dt">void</span> foo<span class="op">(</span>Foo<span class="op">...)</span></code>
is ordered immediately after the type of <code class="sourceCode cpp"><span class="dt">void</span> foo<span class="op">(</span>Foo<span class="op">)</span></code>.</p>
<p>We can represent these as:</p>
<p><code class="sourceCode cpp"><span class="op">(</span>function <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span> <span class="op">(</span>type, Foo, <span class="op">))</span></code></p>
<p><code class="sourceCode cpp"><span class="op">(</span>function <span class="op">(</span>type, <span class="dt">void</span><span class="op">)</span> <span class="op">(</span>type, Foo, <span class="op">...))</span></code></p>
<h4 data-number="14.12.4.7" id="parameter-packs"><span class="header-section-number">14.12.4.7</span> Parameter Packs<a href="#parameter-packs" class="self-link"></a></h4>
<p>Parameter are ordered as class templates.</p>
<p>Given:</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Types<span class="op">&gt;</span></span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Tuple <span class="op">{}</span>;</span>
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{}</span>;</span>
<span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Bar <span class="op">{}</span>;</span>
<span id="cb59-6"><a href="#cb59-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb59-7"><a href="#cb59-7" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;&gt;</span> t0;</span>
<span id="cb59-8"><a href="#cb59-8" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> t1;</span>
<span id="cb59-9"><a href="#cb59-9" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span>Foo<span class="op">&gt;</span> t2;</span>
<span id="cb59-10"><a href="#cb59-10" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span>Bar<span class="op">&gt;</span> t3;</span>
<span id="cb59-11"><a href="#cb59-11" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span>Foo, Bar<span class="op">&gt;</span> t4;</span></code></pre></div>
<p>would be ordered: <code class="sourceCode cpp">Tuple<span class="op">&lt;&gt;</span></code> &lt;
<code class="sourceCode cpp">Tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>
&lt; <code class="sourceCode cpp">Tuple<span class="op">&lt;</span>Bar<span class="op">&gt;</span></code>
&lt; <code class="sourceCode cpp">Tuple<span class="op">&lt;</span>Foo<span class="op">&gt;</span></code>
&lt; <code class="sourceCode cpp">Tuple<span class="op">&lt;</span>Foo, Bar<span class="op">&gt;</span></code></p>
<h4 data-number="14.12.4.8" id="ordering-class-templates"><span class="header-section-number">14.12.4.8</span> Ordering Class
Templates<a href="#ordering-class-templates" class="self-link"></a></h4>
<p>Kinds of templates are ordered first by name, then by template
arguments.</p>
<p>Given:</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> Template<span class="op">&gt;</span></span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> two<span class="op">{}</span>;</span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> one<span class="op">{}</span>;</span>
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">struct</span> zero<span class="op">{}</span>;</span>
<span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-8"><a href="#cb60-8" aria-hidden="true" tabindex="-1"></a>zero<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> value0;</span>
<span id="cb60-9"><a href="#cb60-9" aria-hidden="true" tabindex="-1"></a>one<span class="op">&lt;</span>zero<span class="op">&gt;</span> value1;</span>
<span id="cb60-10"><a href="#cb60-10" aria-hidden="true" tabindex="-1"></a>two<span class="op">&lt;</span>one<span class="op">&gt;</span> value2;</span></code></pre></div>
<p>These are represented by tuples:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>zero<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(</span>zero, <span class="op">(</span>type, <span class="dt">int</span><span class="op">)))</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>one<span class="op">&lt;</span>zero<span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(</span>one, <span class="op">(</span>class_template, zero<span class="op">))))</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>two<span class="op">&lt;</span>one<span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">(</span>two, <span class="op">(</span>class_template, one<span class="op">))))</span></code></p>
<h4 data-number="14.12.4.9" id="variable-templates"><span class="header-section-number">14.12.4.9</span> Variable Templates<a href="#variable-templates" class="self-link"></a></h4>
<p>Variable templates are ordered by name, then by template
parameter.</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>variable_template<span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>variable_template, <span class="op">(&lt;</span>name<span class="op">&gt;</span>, <span class="op">(</span>sort_key<span class="op">(&lt;</span>template_parameter<span class="op">&gt;)...)))</span></code></p>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> F, <span class="kw">typename</span> S<span class="op">&gt;</span></span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>pair<span class="op">&lt;</span>F, S<span class="op">&gt;</span> pair_one_two <span class="op">=</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span>;</span></code></pre></div>
<p>the type of <code class="sourceCode cpp">pair_one_two<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">double</span><span class="op">&gt;</span></code>
can be represented as:</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>pair_one_two<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">double</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>variable_template, <span class="op">(</span>pair_one_two, <span class="op">(</span>type, <span class="dt">int</span><span class="op">)</span>, <span class="op">(</span>type, <span class="dt">double</span><span class="op">)))</span></code></p>
<h4 data-number="14.12.4.10" id="alias-templates"><span class="header-section-number">14.12.4.10</span> Alias Templates<a href="#alias-templates" class="self-link"></a></h4>
<p>Alias templates are ordered alphabetically by name.</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span>alias_template<span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span>alias_template, <span class="op">&lt;</span>name<span class="op">&gt;)</span></code></p>
<p>Given</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-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="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> remove_cvref_t <span class="op">=</span> <span class="kw">typename</span> remove_cvref<span class="op">&lt;</span>T<span class="op">&gt;::</span>type;</span></code></pre></div>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>remove_cvref_t<span class="op">)</span> <span class="op">=</span> <span class="op">(</span>alias_template, remove_cvref_t<span class="op">)</span></code></p>
<h4 data-number="14.12.4.11" id="concepts"><span class="header-section-number">14.12.4.11</span> Concepts<a href="#concepts" class="self-link"></a></h4>
<p>Concepts are ordered in a similar manner to variable templates.</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(&lt;</span><span class="kw">concept</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span><span class="kw">concept</span>, <span class="op">(&lt;</span>name<span class="op">&gt;</span>, <span class="op">(</span>sort_key<span class="op">(&lt;</span>template_parameter<span class="op">&gt;)...)))</span></code></p>
<div class="sourceCode" id="cb63"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> F <span class="op">=</span> <span class="kw">decltype</span><span class="op">([](</span>T<span class="op">){})&gt;</span> </span>
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> f <span class="op">=</span> <span class="kw">requires</span> <span class="op">(</span>T i, F f <span class="op">=</span> <span class="op">[](</span>T<span class="op">){})</span> <span class="op">{</span></span>
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span>f<span class="op">(</span>i<span class="op">)}</span> <span class="op">-&gt;</span> std<span class="op">::</span>convertible_to<span class="op">&lt;</span><span class="dt">void</span><span class="op">&gt;</span>;</span>
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>In order to order the type of the lambda declared in
<code class="sourceCode cpp"><span class="kw">concept</span> f</code>,
<code class="sourceCode cpp"><span class="kw">concept</span> f</code>
must be comparable with other types.</p>
<p>Concepts shall be ordered first by name, then by template
arguments.</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>f<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span> <span class="op">=</span> <span class="op">(</span><span class="kw">concept</span>, <span class="op">(</span>f, <span class="op">(</span>type, <span class="dt">int</span><span class="op">)</span>, <span class="op">(</span>lambda, <span class="dv">0</span><span class="op">)))</span></code></p>
<h1 data-number="15" id="bibliography"><span class="header-section-number">15</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P1985R3" class="csl-entry" role="doc-biblioentry">
[P1985R3] Gašper Ažman, Mateusz Pusz, Colin MacLean, Bengt Gustafsonn,
Corentin Jabot. 2022-09-17. Universal template parameters. <a href="https://wg21.link/p1985r3"><div class="csl-block">https://wg21.link/p1985r3</div></a>
</div>
<div id="ref-P2300R7" class="csl-entry" role="doc-biblioentry">
[P2300R7] Eric Niebler, Michał Dominiak, Georgy Evtushenko, Lewis Baker,
Lucian Radu Teodorescu, Lee Howes, Kirk Shoop, Michael Garland, Bryce
Adelstein Lelbach. 2023-04-21. `std::execution`. <a href="https://wg21.link/p2300r7"><div class="csl-block">https://wg21.link/p2300r7</div></a>
</div>
<div id="ref-P2320R0" class="csl-entry" role="doc-biblioentry">
[P2320R0] Andrew Sutton, Wyatt Childers, Daveed Vandevoorde. 2021-02-15.
The Syntax of Static Reflection. <a href="https://wg21.link/p2320r0"><div class="csl-block">https://wg21.link/p2320r0</div></a>
</div>
<div id="ref-P2841R1" class="csl-entry" role="doc-biblioentry">
[P2841R1] Corentin Jabot, Gašper Ažman. 2023-10-14. Concept Template
Parameters. <a href="https://wg21.link/p2841r1"><div class="csl-block">https://wg21.link/p2841r1</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
