<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-04-09" />
  <title>Standardized 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">Standardized Constexpr Type
Ordering</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2830R3</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-04-09</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>
      EWG<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="#canonicalizing-policy-based-libraries" id="toc-canonicalizing-policy-based-libraries"><span class="toc-section-number">3.1.1</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.2</span> Canonicalized
variant<span></span></a></li>
<li><a href="#canonicalized-tuple" id="toc-canonicalized-tuple"><span class="toc-section-number">3.1.3</span> Canonicalized
tuple<span></span></a></li>
<li><a href="#api-stability" id="toc-api-stability"><span class="toc-section-number">3.1.4</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="#why-implementation-defined" id="toc-why-implementation-defined"><span class="toc-section-number">4.1</span> Why
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.1.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.1.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.1.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.1.4</span> <code class="sourceCode cpp">TYPE_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="#desirable-properties-of-type_orderx-y" id="toc-desirable-properties-of-type_orderx-y"><span class="toc-section-number">4.2</span> Desirable properties of <code class="sourceCode cpp">TYPE_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.2.1</span> Stability<span></span></a></li>
<li><a href="#free-standing" id="toc-free-standing"><span class="toc-section-number">4.2.2</span>
Free-standing<span></span></a></li>
<li><a href="#consistency-with-type_infobefore" id="toc-consistency-with-type_infobefore"><span class="toc-section-number">4.2.3</span> Consistency with <code class="sourceCode cpp">type_info<span class="op">::</span>before<span class="op">()</span></code><span></span></a></li>
<li><a href="#self-consistency" id="toc-self-consistency"><span class="toc-section-number">4.2.4</span>
Self-consistency<span></span></a></li>
<li><a href="#reflection-compatibility" id="toc-reflection-compatibility"><span class="toc-section-number">4.2.5</span> Reflection
compatibility<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="#syntax" id="toc-syntax"><span class="toc-section-number">5.2</span> Syntax<span></span></a>
<ul>
<li><a href="#option-1-preferred-a-variable-template-stdtype_order_vt-u" id="toc-option-1-preferred-a-variable-template-stdtype_order_vt-u"><span class="toc-section-number">5.2.1</span> Option 1 (preferred): a variable
template <code class="sourceCode cpp">std<span class="op">::</span>type_order_v<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#option-2-variable-template-stdentity_orderingx-y" id="toc-option-2-variable-template-stdentity_orderingx-y"><span class="toc-section-number">5.2.2</span> Option 2: 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="#option-3-reflection" id="toc-option-3-reflection"><span class="toc-section-number">5.2.3</span> Option 3:
reflection<span></span></a></li>
<li><a href="#option-4-heterogeneous-constexpr-stdtype_identityoperator" id="toc-option-4-heterogeneous-constexpr-stdtype_identityoperator"><span class="toc-section-number">5.2.4</span> Option 4: 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><span></span></a></li>
<li><a href="#option-5-constexpr-std__liftargoperator" id="toc-option-5-constexpr-std__liftargoperator"><span class="toc-section-number">5.2.5</span> Option 5: <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><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">5.2.6</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>
</ul></li>
<li><a href="#faq" id="toc-faq"><span class="toc-section-number">6</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">6.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">6.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">6.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">7</span>
Implementability<span></span></a></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">8</span> Proposed
Wording<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-full-order-proposal-former-alternative" id="toc-appendix-full-order-proposal-former-alternative"><span class="toc-section-number">10</span> Appendix: full order proposal
(former alternative)<span></span></a>
<ul>
<li><a href="#approach" id="toc-approach"><span class="toc-section-number">10.1</span> Approach<span></span></a></li>
<li><a href="#structure-of-key-tuples" id="toc-structure-of-key-tuples"><span class="toc-section-number">10.2</span> Structure of
key-tuples<span></span></a></li>
<li><a href="#named-scopes" id="toc-named-scopes"><span class="toc-section-number">10.3</span> Named Scopes<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">10.3.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">10.3.2</span> Example:<span></span></a></li>
</ul></li>
<li><a href="#atoms" id="toc-atoms"><span class="toc-section-number">10.4</span> Atoms<span></span></a></li>
<li><a href="#kinds" id="toc-kinds"><span class="toc-section-number">10.5</span> Kinds<span></span></a>
<ul>
<li><a href="#identifiers" id="toc-identifiers"><span class="toc-section-number">10.5.1</span>
Identifiers<span></span></a></li>
<li><a href="#namespaces" id="toc-namespaces"><span class="toc-section-number">10.5.2</span>
Namespaces<span></span></a></li>
<li><a href="#types" id="toc-types"><span class="toc-section-number">10.5.3</span> Types<span></span></a></li>
<li><a href="#ordering-scalar-types" id="toc-ordering-scalar-types"><span class="toc-section-number">10.5.4</span> Ordering Scalar
Types<span></span></a></li>
<li><a href="#ordering-array-types" id="toc-ordering-array-types"><span class="toc-section-number">10.5.5</span> Ordering Array
Types<span></span></a></li>
<li><a href="#ordering-class-types" id="toc-ordering-class-types"><span class="toc-section-number">10.5.6</span> Ordering Class
Types<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#appendix-a-building-apply_canonicalized" id="toc-appendix-a-building-apply_canonicalized"><span class="toc-section-number">11</span> Appendix A: 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="#bibliography" id="toc-bibliography"><span class="toc-section-number">12</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 ordering of types in C++, and
possible syntaxes for it.</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_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_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>
</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). 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_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_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_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_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_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="canonicalizing-policy-based-libraries"><span class="header-section-number">3.1.1</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="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">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="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> 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="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>                    <span class="op">~~~~~~</span> flipped <span class="op">~~~~~~~~~~~~~~~</span></span>
<span id="cb2-3"><a href="#cb2-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="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="dt">int</span> sum <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> pipeline1 <span class="op">=</span> </span>
<span id="cb3-3"><a href="#cb3-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="cb3-4"><a href="#cb3-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="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> pipeline2 <span class="op">=</span> </span>
<span id="cb3-6"><a href="#cb3-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="cb3-7"><a href="#cb3-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.2" id="canonicalized-variant"><span class="header-section-number">3.1.2</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="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="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="cb4-2"><a href="#cb4-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_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_ORDER<span class="op">(</span>x, y<span class="op">)</span></code>.
After we define <code class="sourceCode cpp">TYPE_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_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.2.1" id="multiple-error-kinds-and-stdexpected"><span class="header-section-number">3.1.2.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="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">auto</span> read_packet<span class="op">(</span>socket<span class="op">&amp;</span> sock<span class="op">)</span></span>
<span id="cb5-2"><a href="#cb5-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="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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Decoder<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-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="cb6-3"><a href="#cb6-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="cb6-4"><a href="#cb6-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="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><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-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="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-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.2.2" id="suspension-point-storage-for-asynchronous-code"><span class="header-section-number">3.1.2.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="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>variant<span class="op">&lt;</span></span>
<span id="cb8-2"><a href="#cb8-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="cb8-3"><a href="#cb8-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="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    closure_tuple<span class="op">&lt;</span>set_error, <span class="op">...&gt;</span>,</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">...</span></span>
<span id="cb8-6"><a href="#cb8-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="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-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.2.3" id="compositional-state-machine-models"><span class="header-section-number">3.1.2.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.3" id="canonicalized-tuple"><span class="header-section-number">3.1.3</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="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-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="cb10-2"><a href="#cb10-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="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="co">// or</span></span>
<span id="cb10-4"><a href="#cb10-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="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">auto</span> ss <span class="op">=</span> std<span class="op">::</span>stop_source<span class="op">()</span>;</span>
<span id="cb11-2"><a href="#cb11-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="cb11-3"><a href="#cb11-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="cb11-4"><a href="#cb11-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="cb11-5"><a href="#cb11-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="cb11-6"><a href="#cb11-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.4" id="api-stability"><span class="header-section-number">3.1.4</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="cb12"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>do_something()</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    | error_if_odd()          // there is no semantic change</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    | error_if_we_too_long()  // if we flip these lines</span>
<span id="cb12-4"><a href="#cb12-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. This is still included as the
alternative proposal, should EWG want us to go that way.</p>
<h2 data-number="4.1" id="why-implementation-defined"><span class="header-section-number">4.1</span> Why implementation-defined?<a href="#why-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.</p>
<h3 data-number="4.1.1" id="abi-specifications-already-have-to-do-this-work"><span class="header-section-number">4.1.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="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-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="cb13-2"><a href="#cb13-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="cb13-3"><a href="#cb13-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="cb13-4"><a href="#cb13-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.1.2" id="the-c-standard-doesnt-own-cross-compilation-unit-semantics"><span class="header-section-number">4.1.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.1.3" id="any-new-proposal-to-c-would-have-to-consider-the-ordering"><span class="header-section-number">4.1.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.1.4" id="type_orderx-y-already-has-public-facing-api-implications"><span class="header-section-number">4.1.4</span> <code class="sourceCode cpp">TYPE_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.2" id="desirable-properties-of-type_orderx-y"><span class="header-section-number">4.2</span> Desirable properties of <code class="sourceCode cpp">TYPE_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.2.1" id="stability"><span class="header-section-number">4.2.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.2.2" id="free-standing"><span class="header-section-number">4.2.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.2.3" id="consistency-with-type_infobefore"><span class="header-section-number">4.2.3</span> Consistency with <code class="sourceCode cpp">type_info<span class="op">::</span>before<span class="op">()</span></code><a href="#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_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_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>
<h3 data-number="4.2.4" id="self-consistency"><span class="header-section-number">4.2.4</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_ORDER<span class="op">(</span>T, U<span class="op">)</span> <span class="op">==</span> TYPE_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>
<p>Implementations are encouraged to satisfy this principle, but are not
required to.</p>
<h3 data-number="4.2.5" id="reflection-compatibility"><span class="header-section-number">4.2.5</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>
<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>Regardless of the syntax chosen, the semantics would be the
following.</p>
<p>Let <code class="sourceCode cpp">X</code> and
<code class="sourceCode cpp">Y</code> be (possibly cv-ref) qualified
types.</p>
<p><code class="sourceCode cpp">TYPE_ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
is an 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_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_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_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_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_ORDER<span class="op">(</span>Y, X<span class="op">)</span> <span class="op">==</span></code>std::strong_ordering::greater`
and vice versa</li>
<li>if <code class="sourceCode cpp">TYPE_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_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_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>It is implementation-defined whether the order <code class="sourceCode cpp">TYPE_ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
is finer than the one implied by <code class="sourceCode cpp">std<span class="op">::</span>type_info<span class="op">::</span>before</code>.
That is,</p>
<ul>
<li>if <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></code>,
then <code class="sourceCode cpp">TYPE_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>.</li>
</ul>
<p>Note: the converse is not possible - <code class="sourceCode cpp">TYPE_ORDER<span class="op">(</span>X, Y<span class="op">)</span></code>
does not strip <em>cv-ref</em> qualifiers.</p>
<p>Please also note that <code class="sourceCode cpp">X</code> and
<code class="sourceCode cpp">Y</code> are types (not expressions), and
therefore
<code class="sourceCode cpp"><span class="kw">typeid</span></code> does
not have dynamic typing semantics in this case.</p>
<p>Note: Implementations are encouraged to do this if possible, and
making it “implementation-defined” places a requirement on
implementations to document whether they did so.</p>
<h2 data-number="5.2" id="syntax"><span class="header-section-number">5.2</span> Syntax<a href="#syntax" class="self-link"></a></h2>
<p>Any syntax will do for the use-case, but some better than others.
This section explores the trade-offs in syntax choice.</p>
<p>The authors recommend the first option.</p>
<h3 data-number="5.2.1" id="option-1-preferred-a-variable-template-stdtype_order_vt-u"><span class="header-section-number">5.2.1</span> Option 1 (preferred): a
variable template <code class="sourceCode cpp">std<span class="op">::</span>type_order_v<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code><a href="#option-1-preferred-a-variable-template-stdtype_order_vt-u" class="self-link"></a></h3>
<p>Specifally:</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">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="cb14-2"><a href="#cb14-2" 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_ORDER<span class="op">(</span>T, U<span class="op">)</span>; <span class="co">/* see below */</span></span>
<span id="cb14-3"><a href="#cb14-3" 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="cb14-4"><a href="#cb14-4" 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>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="co">// as a separate library proposal, once member packs make it</span></span>
<span id="cb14-7"><a href="#cb14-7" 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="cb14-8"><a href="#cb14-8" 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="cb14-9"><a href="#cb14-9" 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="cb14-10"><a href="#cb14-10" 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>
<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>We could, in fact, put it into <code class="sourceCode cpp"><span class="op">&lt;</span>compare<span class="op">&gt;</span></code>
if we didn’t want <code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>
to depend on it.</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 should also allow, as a special provision, the arguments to the
above metafunctions to be incomplete.</p>
<h3 data-number="5.2.2" id="option-2-variable-template-stdentity_orderingx-y"><span class="header-section-number">5.2.2</span> Option 2: 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="#option-2-variable-template-stdentity_orderingx-y" class="self-link"></a></h3>
<p>Specifically:</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="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="cb15-2"><a href="#cb15-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_ORDER<span class="op">(</span>X, Y<span class="op">)</span>; <span class="co">/* see below */</span></span>
<span id="cb15-3"><a href="#cb15-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="cb15-4"><a href="#cb15-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>
<h3 data-number="5.2.3" id="option-3-reflection"><span class="header-section-number">5.2.3</span> Option 3: reflection<a href="#option-3-reflection" class="self-link"></a></h3>
<p>Specifically:</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="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="cb16-2"><a href="#cb16-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_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="cb16-3"><a href="#cb16-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>
<h3 data-number="5.2.4" id="option-4-heterogeneous-constexpr-stdtype_identityoperator"><span class="header-section-number">5.2.4</span> Option 4: 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><a href="#option-4-heterogeneous-constexpr-stdtype_identityoperator" class="self-link"></a></h3>
<p>Specifically:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-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="cb17-2"><a href="#cb17-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>
<h3 data-number="5.2.5" id="option-5-constexpr-std__liftargoperator"><span class="header-section-number">5.2.5</span> Option 5: <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><a href="#option-5-constexpr-std__liftargoperator" class="self-link"></a></h3>
<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>
<h3 data-number="5.2.6" id="non-option-constexpr-bool-stdtype_infobefore"><span class="header-section-number">5.2.6</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></h3>
<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="6" id="faq"><span class="header-section-number">6</span> FAQ<a href="#faq" class="self-link"></a></h1>
<h2 data-number="6.1" id="why-should-this-be-standardized"><span class="header-section-number">6.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="6.2" id="why-not-wait-for-reflection"><span class="header-section-number">6.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="6.3" id="but-couldnt-this-be-done-faster-with-reflection"><span class="header-section-number">6.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="7" id="implementability"><span class="header-section-number">7</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.</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.</p>
<h1 data-number="8" id="proposed-wording"><span class="header-section-number">8</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">

<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 : integral_constant&lt;strong_ordering, <em>see below</em>&gt; {};</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class U&gt;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>inline constexpr strong_ordering type_order_v = type_order&lt;T, U&gt;::value;</span></code></pre></div>

</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">
<p><strong>17.11.7: Type Ordering</strong></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
For (possibly <em>cv</em>-qualified) types <em>X</em> and <em>Y</em>,
the expression
<code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code> is a
constant expression <span>7.7
<a href="https://wg21.link/expr.const">[expr.const]</a></span> whose
implementation-defined value is the value of an enumerator of
<code class="sourceCode default">strong_ordering</code>, subject to the
following constraints:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code> is
<code class="sourceCode default">strong_ordering::equal</code> if and
only if <em>X</em> and <em>Y</em> are the same type</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.2.1)</a></span>
<code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code> is
<code class="sourceCode default">strong_ordering::less</code> if and
only if
<code class="sourceCode default"><em>TYPE_ORDER</em>(Y, X)</code> is
<code class="sourceCode default">strong_ordering::greater</code>
(<em>antisymmetry</em>)</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.2.2)</a></span>
for all (possibly <em>cv</em>-qualified) types <em>Z</em>, if both
<code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code> and
<code class="sourceCode default"><em>TYPE_ORDER(Y, Z)</em></code> are
<code class="sourceCode default">strong_ordering::less</code>, then
<code class="sourceCode default"><em>TYPE_ORDER(X, Z)</em></code> is
also <code class="sourceCode default">strong_ordering::less</code>
(<em>transitivity</em>)</li>
</ul></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">type_order</code> denotes a
<em>Cpp17BinaryTypeTrait</em> (20.15.2) with a base characteristic of
<code class="sourceCode default">integral_constant&lt;strong_ordering, <em>TYPE_ORDER(X, Y)</em>&gt;</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Recommended practice</em>: if
<code class="sourceCode default">typeid(X).before(typeid(Y))</code>,
then <code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code>
should be <code class="sourceCode default">strong_ordering::less</code>
if such an implementation is possible on a given platform.
[<em>Note:</em> equivalently:
<code class="sourceCode default"><em>TYPE_ORDER(X, Y)</em></code> should
be a finer order than the one induced by
<code class="sourceCode default">type_info::before</code>;
<code class="sourceCode default">typeid(X)</code> ignores <em>cv</em>
and reference qualifiers. – <em>end note</em>]</p>
</div>
<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>
</ul>
<h1 data-number="10" id="appendix-full-order-proposal-former-alternative"><span class="header-section-number">10</span> Appendix: full order proposal
(former alternative)<a href="#appendix-full-order-proposal-former-alternative" class="self-link"></a></h1>
<p>This is a poor first attempt at figuring out what it would take to
specify this in the C++ standard. It seems like “implementation-defined”
is a better approach.</p>
<h2 data-number="10.1" id="approach"><span class="header-section-number">10.1</span> Approach<a href="#approach" class="self-link"></a></h2>
<ol type="1">
<li>We define a <strong>lowering to a <em>key-tuple</em></strong> for
every entity in the language.</li>
<li>The order is then defined on these <em>key-tuples</em>.</li>
</ol>
<h2 data-number="10.2" id="structure-of-key-tuples"><span class="header-section-number">10.2</span> Structure of key-tuples<a href="#structure-of-key-tuples" class="self-link"></a></h2>
<p>Every <em>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>key-tuple</em></li>
</ul>
<p>These tuples are then ordered lexicographically (ties broken in favor
of shorter tuple), atoms before tuples.</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 paper is concerned with defining this
transformation.</p>
<h2 data-number="10.3" id="named-scopes"><span class="header-section-number">10.3</span> Named Scopes<a href="#named-scopes" class="self-link"></a></h2>
<p>A type is ordered by appending <code class="sourceCode cpp">sort_key<span class="op">(...)</span></code> to
the named scope it is declared in. The following are <em>named
scopes</em>:</p>
<ol type="1">
<li>namespaces</li>
<li>classes</li>
<li>functions</li>
<li>lambdas</li>
<li>concepts</li>
</ol>
<p>Starting with the global namespace, <code class="sourceCode cpp">sort_key<span class="op">(</span>global<span class="op">)</span> <span class="op">=</span> <span class="op">()</span></code>.
Any type <code class="sourceCode cpp">T</code> declared in the global
namespace shall have a defined
<code class="sourceCode cpp">sort_key</code> operation that resolves to
<code class="sourceCode cpp"><span class="op">(</span>sort_key<span class="op">(</span>T<span class="op">))</span></code>.</p>
<h3 data-number="10.3.1" id="example-1-class-foo-is-declared-in-struct-bar"><span class="header-section-number">10.3.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="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-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="cb20"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb20-1"><a href="#cb20-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="10.3.2" id="example"><span class="header-section-number">10.3.2</span> Example:<a href="#example" class="self-link"></a></h3>
<p>Given</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">namespace</span> foo<span class="op">::</span>bar <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> baz <span class="op">{</span></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> j;</span>
<span id="cb21-7"><a href="#cb21-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="10.4" id="atoms"><span class="header-section-number">10.4</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>kinds (see <a href="#kinds">kinds</a>)</li>
<li>simple names (including empty string) (see <a href="#names">names</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>n<span class="op">]</span></code>
(array of known bound n) (ordered by
<code class="sourceCode cpp">n</code> internally)</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>
</ol>
<h2 data-number="10.5" id="kinds"><span class="header-section-number">10.5</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="10.5.1" id="identifiers"><span class="header-section-number">10.5.1</span> Identifiers<a href="#identifiers" class="self-link"></a></h3>
<h4 data-number="10.5.1.1" id="simple-names"><span class="header-section-number">10.5.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="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">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="10.5.1.2" id="anonymous-namespace"><span class="header-section-number">10.5.1.2</span> Anonymous Namespace<a href="#anonymous-namespace" class="self-link"></a></h4>
<p>Anonymous namespaces shall be represented with the ! character, as it
cannot be represented by the empty string and cannot collide with any
user defined names;</p>
<p>Example:</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">namespace</span> a <span class="op">{</span> <span class="kw">namespace</span> <span class="op">{</span> <span class="kw">struct</span> s; <span class="op">}</span> <span class="op">}</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>sort_key<span class="op">(</span>a<span class="op">::</span>s<span class="op">)</span> <span class="op">=</span> <span class="op">((</span><span class="kw">namespace</span>, a<span class="op">)</span>, <span class="op">(</span><span class="kw">namespace</span>, <span class="st">&quot;!&quot;</span><span class="op">)</span>, <span class="op">(</span>type, s, <span class="op">))</span></span></code></pre></div>
<h4 data-number="10.5.1.3" id="unnamed-entities"><span class="header-section-number">10.5.1.3</span> Unnamed entities<a href="#unnamed-entities" class="self-link"></a></h4>
<p>Unnamed entities are all given a name that is not an identifier (but
is, in fact, a tuple), and are then numbered consecutively, starting
with zero, based on their name-scope.</p>
<p>Name-scopes are namespaces, classes, unions, functions, and
enumerations.</p>
<p>Function declarations are name-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="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> T<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-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="cb24-3"><a href="#cb24-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="10.5.1.3.1" id="lambda-types"><span class="header-section-number">10.5.1.3.1</span> Lambda types<a href="#lambda-types" class="self-link"></a></h5>
<p>Types of lambda objects are ordered first by where they are declared,
then by declaration 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 name scope.</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">namespace</span> Banana <span class="op">{</span></span>
<span id="cb25-2"><a href="#cb25-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="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> Apple <span class="op">{</span></span>
<span id="cb25-6"><a href="#cb25-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="cb25-7"><a href="#cb25-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="cb25-8"><a href="#cb25-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="cb26"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>sort_key(decltype(Banana::i)) = ((namespace, Banana), (type, (lambda, 0), ));</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>sort_key(decltype(Apple::i))  = ((namespace, Apple), (type, (lambda, 0), ));</span>
<span id="cb26-3"><a href="#cb26-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="10.5.1.3.2" id="unnamed-struct-and-union-types"><span class="header-section-number">10.5.1.3.2</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>
<h3 data-number="10.5.2" id="namespaces"><span class="header-section-number">10.5.2</span> Namespaces<a href="#namespaces" 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="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="kw">namespace</span> outer1 <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> i;</span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> outer2 <span class="op">{</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">namespace</span> inner1 <span class="op">{</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">namespace</span> inner2 <span class="op">{</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> i;</span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb27-12"><a href="#cb27-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="10.5.3" id="types"><span class="header-section-number">10.5.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 name-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>
<h4 data-number="10.5.3.1" id="qualifiers"><span class="header-section-number">10.5.3.1</span> Qualifiers<a href="#qualifiers" class="self-link"></a></h4>
<p>Qualifiers are each assigned a score</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>&amp;: 1</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>&amp;&amp;: 2</span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>const: 3</span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>volatile: 6</span></code></pre></div>
<p>and ordering lowest-first after summing them.</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="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span>  T</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span>  T <span class="op">&amp;</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span>  T <span class="op">&amp;&amp;</span></span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span>  T <span class="kw">const</span></span>
<span id="cb29-5"><a href="#cb29-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="cb29-6"><a href="#cb29-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="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span>  T <span class="kw">volatile</span></span>
<span id="cb29-8"><a href="#cb29-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="cb29-9"><a href="#cb29-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="cb29-10"><a href="#cb29-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="cb29-11"><a href="#cb29-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="cb29-12"><a href="#cb29-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>The remainder of the paper concerns itself only with unqualified
types.</p>
<h3 data-number="10.5.4" id="ordering-scalar-types"><span class="header-section-number">10.5.4</span> Ordering Scalar Types<a href="#ordering-scalar-types" class="self-link"></a></h3>
<p>All scalar types are built-in types, except for enumerations, which
should be ordered according to their namespaced names.</p>
<p>Unfortunately, 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>).</p>
<p>The intention is for built-in scalar types to be ordered before any
compound types.</p>
<p>Built-in types with simple names should be ordered before any types
that reference other 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.</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 floating point types.</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>
<p>Class types shall be ordered according to the rules below, see
[Ordering Compound Types]</p>
<h3 data-number="10.5.5" id="ordering-array-types"><span class="header-section-number">10.5.5</span> Ordering Array Types<a href="#ordering-array-types" class="self-link"></a></h3>
<p>Array types shall be ordered after scalar types but before class
types.</p>
<p>The <code class="sourceCode cpp">sort_key<span class="op">(</span>T<span class="op">[])</span> <span class="op">=</span> <span class="op">([]</span>, sort_key<span class="op">(</span>T<span class="op">))</span></code>
and the <code class="sourceCode cpp">sort_key<span class="op">(</span>T<span class="op">[</span>n<span class="op">])</span> <span class="op">=</span> <span class="op">([</span>n<span class="op">]</span>, sort_key<span class="op">(</span>T<span class="op">))</span></code>.</p>
<p>The intention is to order arrays first internally by element type,
then by rank, then by rank bounds, lowest first. Arrays of unknown
bounds come before arrays of known bounds.</p>
<p>So the order of the following, for a given type T:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>T<span class="op">[]</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>T<span class="op">[</span><span class="dv">10</span><span class="op">]</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>T<span class="op">[</span><span class="dv">11</span><span class="op">]</span></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>T<span class="op">[][</span><span class="dv">2</span><span class="op">]</span></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>T<span class="op">[</span><span class="dv">10</span><span class="op">][</span><span class="dv">2</span><span class="op">]</span></span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a>T<span class="op">[</span><span class="dv">3</span><span class="op">][</span><span class="dv">2</span><span class="op">]</span></span></code></pre></div>
<p>shall be ordered <code class="sourceCode cpp">T<span class="op">[]</span> <span class="op">&lt;</span> T<span class="op">[</span><span class="dv">10</span><span class="op">]</span> <span class="op">&lt;</span> T<span class="op">[</span><span class="dv">11</span><span class="op">]</span> <span class="op">&lt;</span> T<span class="op">[][</span><span class="dv">2</span><span class="op">]</span> <span class="op">&lt;</span> T<span class="op">[</span><span class="dv">3</span><span class="op">][</span><span class="dv">2</span><span class="op">]</span> <span class="op">&lt;</span> T<span class="op">[</span><span class="dv">10</span><span class="op">][</span><span class="dv">2</span><span class="op">]</span></code>,
and</p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>T<span class="op">[</span><span class="dv">0</span><span class="op">])</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">([]</span>, <span class="op">(</span>type, T, <span class="op">)))</span></code></p>
<p><code class="sourceCode cpp">sort_key<span class="op">(</span>T<span class="op">[</span><span class="dv">10</span><span class="op">][</span><span class="dv">2</span><span class="op">])</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">([</span><span class="dv">2</span><span class="op">]</span>, sort_key<span class="op">(</span>T<span class="op">[</span><span class="dv">10</span><span class="op">])))</span> <span class="op">=</span> <span class="op">(</span>type, <span class="op">([</span><span class="dv">2</span><span class="op">]</span>, <span class="op">(</span>type, <span class="op">([</span><span class="dv">10</span><span class="op">]</span>, <span class="op">(</span>type, T, <span class="op">))))</span></code></p>
<h3 data-number="10.5.6" id="ordering-class-types"><span class="header-section-number">10.5.6</span> Ordering Class Types<a href="#ordering-class-types" class="self-link"></a></h3>
<h4 data-number="10.5.6.1" id="ordering-simple-class-types"><span class="header-section-number">10.5.6.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="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Apple <span class="op">{}</span>;</span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Banana <span class="op">{}</span>;</span>
<span id="cb31-3"><a href="#cb31-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="10.5.6.2" id="non-type-template-parameters"><span class="header-section-number">10.5.6.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="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-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="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> s <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-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="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb32-6"><a href="#cb32-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="cb32-7"><a href="#cb32-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="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-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="cb33-2"><a href="#cb33-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="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> h;</span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> i;</span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> g;</span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> j;</span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-9"><a href="#cb33-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="cb33-10"><a href="#cb33-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="10.5.6.3" id="ordering-class-template-specializations"><span class="header-section-number">10.5.6.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="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-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="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Apple;</span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Banana;</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Carrot;</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a>Apple<span class="op">&lt;</span>Banana, Carrot<span class="op">&gt;</span>;</span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a>Apple<span class="op">&lt;</span>Banana, Banana<span class="op">&gt;</span>;</span>
<span id="cb34-9"><a href="#cb34-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="10.5.6.4" id="function-types"><span class="header-section-number">10.5.6.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>Return type</li>
<li>Parameters, lexicographically.</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>, 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="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-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="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="dt">void</span> foo<span class="op">(</span><span class="dt">int</span><span class="op">)</span></span>
<span id="cb36-2"><a href="#cb36-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="10.5.6.5" id="member-function-types"><span class="header-section-number">10.5.6.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="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Foo <span class="op">{</span></span>
<span id="cb37-2"><a href="#cb37-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="cb37-3"><a href="#cb37-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="10.5.6.6" id="variadic-function-types"><span class="header-section-number">10.5.6.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="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-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="cb38-2"><a href="#cb38-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="10.5.6.7" id="parameter-packs"><span class="header-section-number">10.5.6.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="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-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="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Tuple <span class="op">{}</span>;</span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Foo <span class="op">{}</span>;</span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Bar <span class="op">{}</span>;</span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;&gt;</span> t0;</span>
<span id="cb39-8"><a href="#cb39-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="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span>Foo<span class="op">&gt;</span> t2;</span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a>Tuple<span class="op">&lt;</span>Bar<span class="op">&gt;</span> t3;</span>
<span id="cb39-11"><a href="#cb39-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="10.5.6.8" id="ordering-class-templates"><span class="header-section-number">10.5.6.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="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-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="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> two<span class="op">{}</span>;</span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-4"><a href="#cb40-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="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-6"><a href="#cb40-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="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-8"><a href="#cb40-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="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a>one<span class="op">&lt;</span>zero<span class="op">&gt;</span> value1;</span>
<span id="cb40-10"><a href="#cb40-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="10.5.6.9" id="variable-templates"><span class="header-section-number">10.5.6.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="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-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="cb41-2"><a href="#cb41-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="10.5.6.10" id="alias-templates"><span class="header-section-number">10.5.6.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="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-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="cb42-2"><a href="#cb42-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="10.5.6.11" id="concepts"><span class="header-section-number">10.5.6.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="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">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="cb43-2"><a href="#cb43-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="cb43-3"><a href="#cb43-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="cb43-4"><a href="#cb43-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="11" id="appendix-a-building-apply_canonicalized"><span class="header-section-number">11</span> Appendix A: building
<code class="sourceCode cpp">apply_canonicalized</code><a href="#appendix-a-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="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> undefined;</span>
<span id="cb44-2"><a href="#cb44-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="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-4"><a href="#cb44-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="cb44-5"><a href="#cb44-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="cb44-6"><a href="#cb44-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="cb44-7"><a href="#cb44-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="cb44-8"><a href="#cb44-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="cb44-9"><a href="#cb44-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="cb44-10"><a href="#cb44-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="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-12"><a href="#cb44-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="cb44-13"><a href="#cb44-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="cb44-14"><a href="#cb44-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="cb44-15"><a href="#cb44-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="cb44-16"><a href="#cb44-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="cb44-17"><a href="#cb44-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="cb44-18"><a href="#cb44-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="cb44-19"><a href="#cb44-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="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-21"><a href="#cb44-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="cb44-22"><a href="#cb44-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="cb44-23"><a href="#cb44-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="cb44-24"><a href="#cb44-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-25"><a href="#cb44-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="cb44-26"><a href="#cb44-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="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">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="cb45-2"><a href="#cb45-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="cb45-3"><a href="#cb45-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="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="co">// a canonicalized T is just T</span></span>
<span id="cb45-6"><a href="#cb45-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="cb45-7"><a href="#cb45-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="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-9"><a href="#cb45-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="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a>concatenate<span class="op">&lt;</span></span>
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// canonicalized things less than T</span></span>
<span id="cb45-12"><a href="#cb45-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_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="cb45-13"><a href="#cb45-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="cb45-14"><a href="#cb45-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// canonicalized things greater than T</span></span>
<span id="cb45-15"><a href="#cb45-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_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="cb45-16"><a href="#cb45-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;</span> <span class="co">//                                     ~~~~~~~~~~~~~~~~</span></span>
<span id="cb45-17"><a href="#cb45-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="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">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="cb46-2"><a href="#cb46-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="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="pp">#include </span><span class="im">&lt;compare&gt;</span></span>
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> undefined;</span>
<span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#define TYPE_ORDER</span><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="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-8"><a href="#cb47-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="cb47-9"><a href="#cb47-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="cb47-10"><a href="#cb47-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-11"><a href="#cb47-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="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> undefined _apply;</span>
<span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-14"><a href="#cb47-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="cb47-15"><a href="#cb47-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="cb47-16"><a href="#cb47-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="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-18"><a href="#cb47-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="cb47-19"><a href="#cb47-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="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-21"><a href="#cb47-21" aria-hidden="true" tabindex="-1"></a><span class="co">// some user-type</span></span>
<span id="cb47-22"><a href="#cb47-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="cb47-23"><a href="#cb47-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="cb47-24"><a href="#cb47-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="cb47-25"><a href="#cb47-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="cb47-26"><a href="#cb47-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-27"><a href="#cb47-27" aria-hidden="true" tabindex="-1"></a><span class="co">// built-in</span></span>
<span id="cb47-28"><a href="#cb47-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="cb47-29"><a href="#cb47-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="cb47-30"><a href="#cb47-30" aria-hidden="true" tabindex="-1"></a>    x <span class="op">&lt;=&gt;</span> y;</span>
<span id="cb47-31"><a href="#cb47-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-32"><a href="#cb47-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="cb47-33"><a href="#cb47-33" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> list <span class="op">{}</span>;</span>
<span id="cb47-34"><a href="#cb47-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-35"><a href="#cb47-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="cb47-36"><a href="#cb47-36" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> undefined _concatenate;</span>
<span id="cb47-37"><a href="#cb47-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="cb47-38"><a href="#cb47-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="cb47-39"><a href="#cb47-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="cb47-40"><a href="#cb47-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="cb47-41"><a href="#cb47-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="cb47-42"><a href="#cb47-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-43"><a href="#cb47-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="cb47-44"><a href="#cb47-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="cb47-45"><a href="#cb47-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-46"><a href="#cb47-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="cb47-47"><a href="#cb47-47" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _select;</span>
<span id="cb47-48"><a href="#cb47-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="cb47-49"><a href="#cb47-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="cb47-50"><a href="#cb47-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-51"><a href="#cb47-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="cb47-52"><a href="#cb47-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="cb47-53"><a href="#cb47-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-54"><a href="#cb47-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="cb47-55"><a href="#cb47-55" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> list<span class="op">&lt;&gt;</span> _canon;</span>
<span id="cb47-56"><a href="#cb47-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="cb47-57"><a href="#cb47-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="cb47-58"><a href="#cb47-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-59"><a href="#cb47-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="cb47-60"><a href="#cb47-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="cb47-61"><a href="#cb47-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-62"><a href="#cb47-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="cb47-63"><a href="#cb47-63" aria-hidden="true" tabindex="-1"></a>concatenate<span class="op">&lt;</span></span>
<span id="cb47-64"><a href="#cb47-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_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="cb47-65"><a href="#cb47-65" aria-hidden="true" tabindex="-1"></a>    list<span class="op">&lt;</span>T<span class="op">&gt;</span>,</span>
<span id="cb47-66"><a href="#cb47-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_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="cb47-67"><a href="#cb47-67" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;</span></span>
<span id="cb47-68"><a href="#cb47-68" aria-hidden="true" tabindex="-1"></a>_canon<span class="op">&lt;</span>T, Ts<span class="op">...&gt;</span>;</span>
<span id="cb47-69"><a href="#cb47-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-70"><a href="#cb47-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-71"><a href="#cb47-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="bibliography"><span class="header-section-number">12</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>
