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

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
div.std blockquote { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
div.std.ins blockquote {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.ins > div.example {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.std div.sourceCode { background-color: inherit; margin-left: 1em; }
div.std blockquote del { text-decoration: line-through;
color: #000000; background-color: var(--diff-del);
border: none; }
code del { border: 1px solid #ECB3C7; }
span.orange {
background-color: #ffa500;
}
span.yellow {
background-color: #ffff00;
}</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">Extending support for class
types as non-type template parameters</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3380R0 <a href="https://wg21.link/P3380">[Latest]</a> <a href="https://wg21.link/P3380/status">[Status]</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-09-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>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="#serialization" id="toc-serialization"><span class="toc-section-number">1.1</span>
Serialization<span></span></a></li>
<li><a href="#normalization" id="toc-normalization"><span class="toc-section-number">1.2</span>
Normalization<span></span></a></li>
<li><a href="#deserialization" id="toc-deserialization"><span class="toc-section-number">1.3</span>
Deserialization<span></span></a></li>
<li><a href="#soundness" id="toc-soundness"><span class="toc-section-number">1.4</span> Soundness<span></span></a></li>
<li><a href="#original-design" id="toc-original-design"><span class="toc-section-number">1.5</span> Original
Design<span></span></a></li>
</ul></li>
<li><a href="#reflection-will-fix-it" id="toc-reflection-will-fix-it"><span class="toc-section-number">2</span> Reflection Will Fix
It<span></span></a>
<ul>
<li><a href="#interesting-edge-case" id="toc-interesting-edge-case"><span class="toc-section-number">2.1</span> Interesting Edge
Case<span></span></a></li>
<li><a href="#alternate-spelling" id="toc-alternate-spelling"><span class="toc-section-number">2.2</span> Alternate
Spelling<span></span></a></li>
<li><a href="#splitting" id="toc-splitting"><span class="toc-section-number">2.3</span> Splitting<span></span></a></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">3</span> Proposal<span></span></a>
<ul>
<li><a href="#language" id="toc-language"><span class="toc-section-number">3.1</span> Language<span></span></a></li>
<li><a href="#library" id="toc-library"><span class="toc-section-number">3.2</span> Library<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">4</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span>
Introduction<a href="#introduction" class="self-link"></a></h1>
<p>This paper is conceptually a follow-up to <span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span>, except that it’s largely a new
design, and I haven’t heard back from Richard Smith and didn’t want to
put his name on ideas I’m not sure he agrees with, despite everything in
this paper being derived from his insights.</p>
<p>Recommended reading in advance:</p>
<ul>
<li><span class="citation" data-cites="P0732R2">[<a href="https://wg21.link/p0732r2" role="doc-biblioref">P0732R2</a>]</span> first introduced class types as
non-type template parameters, based on defaulted
<code class="sourceCode cpp"><span class="op">&lt;=&gt;</span></code>.
This got later changed to be based on defaulted
<code class="sourceCode cpp"><span class="op">==</span></code>.</li>
<li><span class="citation" data-cites="P1907R0">[<a href="https://wg21.link/p1907r0" role="doc-biblioref">P1907R0</a>]</span> pointed out issues and
limitations in this approach</li>
<li><span class="citation" data-cites="P1907R1">[<a href="https://wg21.link/p1907r1" role="doc-biblioref">P1907R1</a>]</span> was a revised design based on
the concept of structural types, not equality, and was what was adopted
for C++20.</li>
<li>Davis Herring has a great StackOverflow answer <a href="https://stackoverflow.com/questions/63694879/floating-point-types-as-template-parameter-in-c20/63714924#63714924">here</a>
detailing a lot of these issues.</li>
<li><span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span> was an idea for C++23 to extend
support for class types as non-type template parameters to handle many
of the remaining easy cases.</li>
<li>A <a href="https://brevzin.github.io/c++/2024/08/15/cnttp/">blog
post</a> I wrote on this topic</li>
</ul>
<p>The status quo right now is that class types that have all of their
subobjects public and structural can be used as non-type template
parameters. This was an extremely useful addition to C++20, but leaves a
lot to be desired. The goal of this paper is to provide a design that
will allow all types to be usable as non-type template parameters,
provided the correct opt-in. In order to do so, I have to first
introduce three concepts: serialization, normalization, and
deserialization.</p>
<h2 data-number="1.1" id="serialization"><span class="header-section-number">1.1</span> Serialization<a href="#serialization" class="self-link"></a></h2>
<p>All the work at this point has established pretty clearly that
template argument equivalence is a serialization problem. What the
defaulted-<code class="sourceCode cpp"><span class="op">&lt;=&gt;</span></code>
design established, and then the
defaulted-<code class="sourceCode cpp"><span class="op">==</span></code>
design and the structural type design preserved, was that we need to
treat a class type as being comprised of a bunch of scalar types and
having equivalence be based on those scalars.</p>
<p>However we generalize the non-type template parameter problem to more
interesting class types is going to require a mechanism for the user to
tell the compiler how their class decomposes. Put differently: how can
the compiler serialize your class.</p>
<p>More formally, serialization takes a value
<code class="sourceCode cpp">v</code> and explodes it into some tuple of
structural types:</p>
<p><img src="data:image/png;base64,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" alt /></p>
<p>Since the resulting types have to themselves be structural, that
means they themselves can be (recursively) serialized. Regardless of
what mechanism we could use to specify serialization, the compiler can
do the recursive part itself without any user input. So in real life it
might look more like this (where the values in the right-most column are
those scalar/pointer/reference types that cannot further decompose):</p>
<p><img src="data:image/png;base64,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" alt /></p>
<p>There are many types for which default subobject-wise serialization
is actually sufficient — types like <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code>,
<code class="sourceCode cpp">std<span class="op">::</span>optional<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
<code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op">&lt;</span>T, E<span class="op">&gt;</span></code>,
<code class="sourceCode cpp">std<span class="op">::</span>variant<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code>,
<code class="sourceCode cpp">std<span class="op">::</span>string_view</code>,
<code class="sourceCode cpp">std<span class="op">::</span>span<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
etc. For such types, the problem reduces to simply coming up with the
right syntax to express that opt-in.</p>
<p>But for other types, simply serializing all the subobjects is
insufficient. We have to do a little bit more.</p>
<h2 data-number="1.2" id="normalization"><span class="header-section-number">1.2</span> Normalization<a href="#normalization" class="self-link"></a></h2>
<p>One of the examples that got brought up frequently during discussion
is:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Fraction <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> num;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> denom;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Should <code class="sourceCode cpp">Fraction<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span></code>
be able to be template-argument-equivalent to <code class="sourceCode cpp">Fraction<span class="op">{</span><span class="dv">2</span>, <span class="dv">4</span><span class="op">}</span></code>?
That is, should the serialization process be allowed to also do
normalization? Maybe you want to minimize your template
instantiations?</p>
<p>I find this particular example difficult to reason about whether it
matters, but there is another that I think is more compelling (courtesy
of Richard Smith). Consider:</p>
<div class="std">
<blockquote>
<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">class</span> SmallString <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> data<span class="op">[</span><span class="dv">32</span><span class="op">]</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> length <span class="op">=</span> <span class="dv">0</span>; <span class="co">// always &lt;= 32</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// the usual string API here, including</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    SmallString<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> data;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> push_back<span class="op">(</span><span class="dt">char</span> c<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>        <span class="ot">assert</span><span class="op">(</span>length <span class="op">&lt;</span> <span class="dv">31</span><span class="op">)</span>;</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>        data<span class="op">[</span>length<span class="op">]</span> <span class="op">=</span> c;</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>length;</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> pop_back<span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>        <span class="ot">assert</span><span class="op">(</span>length <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>        <span class="op">--</span>length;</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>And add a few functions:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>SmallString S<span class="op">&gt;</span> <span class="kw">struct</span> C <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> f<span class="op">()</span> <span class="op">-&gt;</span> SmallString <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> s <span class="op">=</span> SmallString<span class="op">()</span>;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    s<span class="op">.</span>push_back<span class="op">(</span><span class="ch">&#39;x&#39;</span><span class="op">)</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> s;</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> g<span class="op">()</span> <span class="op">-&gt;</span> SmallString <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> s <span class="op">=</span> f<span class="op">()</span>;</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>    s<span class="op">.</span>push_back<span class="op">(</span><span class="ch">&#39;y&#39;</span><span class="op">)</span>;</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    s<span class="op">.</span>pop_back<span class="op">()</span>;</span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> s;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Now, we might consider the values returned by
<code class="sourceCode cpp">f<span class="op">()</span></code> and
<code class="sourceCode cpp">g<span class="op">()</span></code> to be
equal — they’re both strings of length 1 whose single character is
<code class="sourceCode cpp">x</code>. But they have different contents
of their <code class="sourceCode cpp">data</code> arrays. So if we do
default subobject-wise equivalence (i.e. the C++20 rule), then <code class="sourceCode cpp">C<span class="op">&lt;</span>f<span class="op">()&gt;</span></code>
and <code class="sourceCode cpp">C<span class="op">&lt;</span>g<span class="op">()&gt;</span></code>
would be different types. This is unlikely to be the desired effect.</p>
<p>If instead of subobject-wise equivalence, we instead did custom
serialization — if we only serialized the contents of <code class="sourceCode cpp">data<span class="op">[:</span>length<span class="op">]</span></code>
(such that
<code class="sourceCode cpp">f<span class="op">()</span></code> and
<code class="sourceCode cpp">g<span class="op">()</span></code>
serialize identically), then we have a different problem. Consider:</p>
<div class="std">
<blockquote>
<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>SmallString S<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> bad<span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>S<span class="op">.</span>data<span class="op">()[</span><span class="dv">1</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;y&#39;</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">1</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>What do <code class="sourceCode cpp">bad<span class="op">&lt;</span>f<span class="op">()&gt;()</span></code>
and <code class="sourceCode cpp">bad<span class="op">&lt;</span>g<span class="op">()&gt;()</span></code>
evaluate to,
<code class="sourceCode cpp"><span class="dv">0</span></code> or
<code class="sourceCode cpp"><span class="dv">1</span></code>? Or both?
This is an ODR violation, and would be a very bad outcome that we (at
least Richard and I) desperately want to avoid.</p>
<p>So far then we have two options for
<code class="sourceCode cpp">SmallString</code>:</p>
<ol type="1">
<li>Opt-in to member-wise equivalence, which leads to two equal values
being non-equivalent.</li>
<li>Custom serialization, which can lead to ODR violations.</li>
</ol>
<p>Instead, we can do something else. Prior to serialization, we can
optionally perform an extra normalization step. In this case, first we
would normalize the representation (by setting <code class="sourceCode cpp">data<span class="op">[</span>length<span class="op">:</span><span class="dv">32</span><span class="op">]</span></code>
to <code class="sourceCode cpp"><span class="dv">0</span></code>) and
then we would serialize.</p>
<p>Visually:</p>
<p><img src="data:image/png;base64,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" alt /></p>
<p>Which would naturally recurse:</p>
<p><img src="data:image/png;base64,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IiJSJApo4rHy6uYEGDZsGACTJ0++YTWJiIi4ggKaeKxrTRRw6NmzJ3Xq1OHkyZPMmjXrRpYmIiJSJApo4rEcj3zavXt3ruPQAJ555hnA3oqWnp5+w2oTEREpCgU08WitW7cGrt3N2alTJ8LCwjh37hxff/31jSxNRESk0BTQxKNdr5sTYMSIEQBMmzaNxMTEG1KXiIhIUSigiUe73kQBxz7t27fHYrEwadKkG1WaiIhIoSmgiUdr1qwZAHv27OH8+fPX3O+ll14CYM6cORw6dOiG1CYiIlJYCmji8dq2bQvkvh6aQ+3atenXrx8AH3300Q2pS0REpLAU0MTj5aebE2D48OH4+/uzevVqtm/ffiNKExERKRQFNPF4joD2xx9/5Llf+fLlefTRRwF4//33i70uERGRwlJAE48XHh6OyWRi3759JCQk5LnvoEGDKFeuHDExMfz88883qEIREZGCUUATr9CmTRvg+t2cJpOJZ599FoAPPviACxcuFHttIiIiBaWAJl4hv+PQAPr27UuDBg1ISkrSczpFRKREUkATr3DbbbcBsHHjxnzt//rrrwMwY8YMjhw5Umx1iYiIFIYCmniFevXqUaZMGY4fP86xY8euu394eDi9e/cGYNy4ccVdnoiISIEooInXaNeuHXD92ZwOzz//PEFBQWzcuJGVK1cWZ2kiIiIFooAmXsPRzZnfgFauXDmGDh0KwPjx44utLhERkYJSQBOvUdCABjBgwABq1KjBiRMn+Oyzz4qrNBERkQJRQBOvUb16dapWrcqZM2c4cOBAvo976623APjiiy+Ii4srrvJERETyTQFNvErr1q0B2LRpU76PadmypfM5naNHjy6WukRERApCAU28SmG6OQFeeOEFypcvT0xMDLNmzSqO0kRERPJNAU28imPB2vyuh+ZgNpsZOXIkAB9//DEnT550eW0iIiL5pYAmXqVixYrUrVuXtLQ0du/eXaBj7777bjp06EB6ejpjxowppgpFRESuTwFNvE5huzkB3nzzTUwmExs2bGDBggWuLk1ERCRfFNDE6zgCWkEmCjhUqFDB2dX57rvvcuLECZfWJiIikh8KaOJ1WrZsCcDWrVsLdXzv3r3p2LEjFovF+cxOERGRG0kBTbxO2bJladSoERkZGWzbtq1Q5xg1ahShoaHs2LGDqVOnurhCERGRvCmgiVdydHNu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" alt /></p>
<p>With such a normalization step, we can get
<code class="sourceCode cpp">f<span class="op">()</span></code> and
<code class="sourceCode cpp">g<span class="op">()</span></code> to be
template-argument-equivalent in a way that avoids any ODR issues, since
now their representations are actually identical.</p>
<p>However, this still isn’t sufficient…</p>
<h2 data-number="1.3" id="deserialization"><span class="header-section-number">1.3</span> Deserialization<a href="#deserialization" class="self-link"></a></h2>
<p>Consider <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>.
One possible representation of this is:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> vector <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    T<span class="op">*</span> begin_;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> size_;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> capacity_;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>For our purposes it doesn’t matter if
<code class="sourceCode cpp"><span class="dt">size_t</span></code> and
<code class="sourceCode cpp">capacity_</code> are themselves
<code class="sourceCode cpp"><span class="dt">size_t</span></code> or
<code class="sourceCode cpp">T<span class="op">*</span></code>, so I’m
picking the simpler one to reason about.</p>
<p>The template-argument-equivalence rule for pointers is that two
pointers are equivalent if they have the same pointer value. That’s not
what we want for comparing two <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>s
though, we want to compare the contents. In order for the default,
subobject-wise equivalence to work in this case, we’d have to normalize
the pointers to be <em>identical</em>. For <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
specifically, this is potentially feasible using a <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>define_static_array</code>
function that will be proposed as part of the reflection proposal (<span class="citation" data-cites="P2996R5">[<a href="https://wg21.link/p2996r5" role="doc-biblioref">P2996R5</a>]</span>, although it does not appear
yet in that revision). But that’s not going to help us with
<code class="sourceCode cpp">std<span class="op">::</span>map</code>,
<code class="sourceCode cpp">std<span class="op">::</span>list</code>,
or any other container.</p>
<p>For <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
we really need to serialize a variable-length sequence of
<code class="sourceCode cpp">T</code>s.</p>
<p>As we already saw in the previous section, custom serialization (by
which I mean serialization that isn’t simply serializing every
subobject) can lead to ODR violations if two different objects serialize
the same.</p>
<p>This is where deserialization comes in. We say that the template
argument value that the user sees in code is the result of first
serializing the value, and then passing that serialized state back into
the class to construct a new value. Whatever the resulting value that we
get out of deserialization, that is <em>reliably</em> the value of the
template argument for all values of the original type that compare
template-argument-equivalent to each other. We don’t have to worry about
which of a bunch of possible specializations is chosen by the
compiler/linker.</p>
<p>Deserialization actually implicitly does normalization — the
roundtrip of a value through (de)serialization is normalized. But while
ODR problems can be avoided by careful use of normalization, ODR
problems are avoided entirely by construction if we require
deserialization. That’s pretty appealing. And the process can have some
added checks too! The compiler can perform one extra serialization step
to ensure that:</p>
<div class="std">
<blockquote>
<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>serialize<span class="op">(</span>deserialize<span class="op">(</span>serialize<span class="op">(</span>v<span class="op">)))</span> <span class="op">===</span> serialize<span class="op">(</span>v<span class="op">)</span></span></code></pre></div>
</blockquote>
</div>
<p>This check ensures that the round-trip is sound by construction.</p>
<p>In the same way that serialization converts a value into a tuple of
structural types, deserialization starts with that tuple of structural
types and produces a possibly-new value of the original type:</p>
<p><img src="data:image/png;base64,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" alt /></p>
<p>And in the same way that serialization works recursively in a way
that the compiler can take care of for you, deserialization could too.
And it’s important that it work like this for the same reason. So a more
complex diagram might be:</p>
<p><img src="data:image/png;base64,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kfpbvtw6+uPVKW4+N6UCl6ZVAgMDSU9Px2azmY4kIiJSJwUF0KkT2O1QVmY6jef45AhH+/btiYuL4/z582zevNl0HBERkTpzj26MGWM2h6f5ZOGAS9Mq6937wIqIiPigplI4fHJKBaC4uJjExETA2nm0VatWhhOJiIj8MCUl0KaNdV5WZk2r+CufHeFwOBz0798fgIyMDMNpREREfjj3VubDh/t32QAfLhwAI769u80q924pIiIiPqSpTKeAD0+pAJw/f57ExERcLhcrV64kNDTUdCQREZFaKS+HG26wjl99BddfbzqRZ/n0CEdgYGDVKMdK97iUiIiID1i50iobQ4f6f9kAHy8cAKNGjQI0rSIiIr5lyRLr+PDDZnM0Fp8vHL169SI8PJwzZ87oDrIiIuITSkouLRj1591Fq/P5wgEw5tvVNhrlEBERX7BsmXUcMaJpTKeAnxQO9zqODRs2UFJSYjiNiIjI1blv1vbTn5rN0Zj8onBcf/31JCQkALB27VrDaURERK7s7Flwf1Q1hcth3fyicMClxaMffPCB4SQiIiJXlpZmHZOSoHVrs1kak98UjoEDB9KxY0dyc3PZvn276TgiIiLf6913rWNTmk4BPyocAD/99t/e4sWLDScRERH5rtxcyMqCVq1g9GjTaRqXXxWOBx54AJvNxqZNmzh+/LjpOCIiIjW88451HDcObDazWRqbXxWO4OBg7r//fgDedy8BFhER8RJz51rHxx4zm8MEvyocAOPHjwdg+fLluFwuw2lEREQsmzbByZMQEQF33206TePzu8Jx8803079/f1wuFytWrDAdR0REBIAFC6zjL35hNocpflc4AMaNGwfAokWLDCcREREBlwuWLrXOH3/cbBZT/LJw3HXXXURERFBQUMAy9/6xIiIihnzwAZSWQmIi3HST6TRm+GXhAHjqqacAmOteoSMiImKI+6Po1782m8Mkvy0cgwYNokePHpw5c4Y097ZuIiIijWz3bti8GTp2hLFjTacxx28LB0BycjIA8+bNM5xERESaqr/9zTp+O/DeZPl14YiPj68a5VjqXq0jIiLSSL76Ct56yzp/8kmzWUzz68IBMGnSJADeeustysrKDKcREZGm5M03reOECdCundkspvl94RgwYAAxMTGcOXOG119/3XQcERFpQmbPto5PP202hzfw+8IB8Mc//hGAtLQ09u3bZziNiIg0BfPmwfHj0L8/xMWZTmNekygct9xyCykpKQC88MILhtOIiEhTMGOGdZw502wOb9EkCgfA448/TpcuXcjLy2POnDmm44iIiB+bOxfy8qBvX2uzL4FmlZWVlaZDNBan01l1c7f333+frl27Gk4kIiL+qFMnKCiArCwYONB0Gu/QpAoHwOzZs1mwYAE9evTg3XffNR1HRKTJyHi/kGNO77haMCbewe2Dr/fI754zB1JSrJGNjz/2yEv4pCZXOACSkpLIy8sjKSmJ3//+96bjiIg0CavfzKdTt2A6htuN5ji8qxibDfqPuMEjv989urFtmzWlIpYWpgOY8Je//IUJEyawfPlyOnfuXDXNIiIinhVgv46gNmY/eloGNgcqPPK7Z8ywysa996psXK7JLBqtLiIigldffRWA1157jczMTMOJRETE1+XkQGqqda5tn76rSRYOgDvvvJM//OEPAEyZMoXPPvvMcCIREfFlEyZYx9RUiIw0m8UbNdnCATBq1Ch+/vOfAzB58mTy8vIMJxIREV/0979bazYiI+HbvSblMk26cAA8+eSTDB48mJKSEiZNmkRRUZHpSCIi4kNOnYIpU6zzhQvNZvFmTb5wAMyaNYvevXtTUFDAo48+itPpNB1JRER8RFISnDtnXQrbr5/pNN5LheNbc+bM4cc//jEnT55k/PjxpKWlmY4kIiJe7mc/g+xsiImBV14xnca7qXB8y26388orrzB58mQAXn75ZaZNm0Z5ebnhZCIi4o1mzYL33oP27WHdOrCb3V7E66lwXObRRx/ljTfewOFwkJ6eziOPPEJubq7pWCIi4kU+/BCmTbPO166FkBCzeXyBCsf3iIuL47333iMqKoq8vDzGjh3Lyy+/TGFhoeloIiJeo0+fPsTHx/OPf/yDkpKSBvu9e/bsIC/v6Hce37w5g+Liqy/s37t3F8eOefYvicuWwciR1nlaGvTp49GX8xsqHFfQsWNHFi1axPPPP0+HDh1IS0tj+PDhKh4iItWUl5ezYMEChg8fzty5cxukeCxZMp9Vq5bWeMzlcjFz5lT27999xed98UUOU6b8ii++yKl3hit56SV48EHrfPHiS+dybSoc1/DAAw/w0Ucf8eyzz+JwOKqKx4svvsi2bdtMxxMRMe7ChQuUl5czf/78ehePyspKDhz4jA0bPuTixYtVj7uLxuHD338VYVHRWV544Zk6vWZtlJbCE0/A889DmzaQmQkPP+yxl/NLKhy1NH78eNasWcMzzzxD69atWbZsGSkpKQwYMIDf/va3LFu2DKfTSWlpqemoIiJGNETxOH36FOXlZZSXl+F07qt6fNu2fwHUeKz6686cOYUzZxp+9DkvD557DkJDYd4865idDQkJDf5Sfq9J3rytrmw2GxMmTCApKYn09HSys7PZunUrWVlZZGVlVf1cmzZtCAsLo1OnTtx88820bdsWh8NBmzZtcDgcVec33OCZOxWKiJh04cIFLly4wPz581m4cCETJkxg3LhxtXru0aNHqs63bMkgOjqWyspKsrLWA/D553upqKigefNLf19+441X2bdvNw89NJGlS9+uV/aCAjhwAJxOWL8eVqywHrfZ4Kmn4IUXoEOHer1Ek6XCUQfBwcGMHj2a0aNHA7B37162b9/OsWPHOHHiBCdPnmT//v3s37+/Vr/PbrcTGBhIy5YtCQwMJCAgoOqrRQv9KxIR33R58Zj66NJrPic311p/0avXj8jIWMsTTzzLkSOHKCo6S1RUNE7nPvLzTxAaGgbA6tUfsGbN/zJp0n/RpUv3WheOpUtherV9M1wuq2QUF9f8ubZt4emnYfJk6/JXqTt9mjWAmJgYYmJivvN4Xl4eBQUFnDp1itOnT1NYWFjjePr0acBadKX9PkTEX1VWVtb6/3GHDzux24N46KHHSE39DQcP7mf37u0ATJw4ienTUzhy5CChoWHs2bOD2bP/zH33jWHMmIfZu3dXrTMdPw7VBqax26FHD+jZs+ZXjx4/6K3KVahweFBYWBhhYWGmY4iIeESfa1wP2qJFCy5evEhiYiIpKSnsXHPt35mTc4Du3Xty++39sNuD+OSTjezevZ1+/eLp2fNHgFVKunWLIjX1OQDCw7uxZs0yjh+3LqXdtWsrt93WF4ej7RVf57nn4IP0Wr5RaRAqHCIi0qAuLxo33XQTADvJv+rzysrKyM8/wV13JRAQEEBCwrCqKZKpU2dgs9kIDb0Fp3Mf3bpFAWC3B7FgwRwAysvLAFi3bhVJSY9ctXBI41PhEBGRBnGlolFb+fnHAWvEAmDgwKGsXWut2uzbdwAAUVHRpKd/xEsv/Q8DBw6p8fy9e3cxZcqvmD79RSIiutX37UgD02WxIiJSL+7F7YmJiaxatYo//elPP7hsAJw4cQyA8PCuAMTE3IHdHkS/fvG0bt0GgC5dugNw8mReQ0SXRqQRDhERqZe6jmhczj3CERYWAVhFZujQ+4mKiq76mS5dIgHIzT1MWFh4jee7L5WtfsmseI9mlZWVlaZDiIiI/1v9Zj6dezsIjQyq9XNKS8/RsqW1TUBDOZB9luuaVdB/hPZCakwa4RAREa/VqlWw6QjSQDTuJCIiIh6nwiEiIiIep8IhIiIiHqfCISIiIh6nwiEiIiIep8IhIiIiHqfCISIiIh6nwiEiIiIep42/RESkUTRrBp9+eIrrWjYzmuPi+Qqi73YYzdAUaWtzERFpFK7SCi5eqDAdA4AAW3MCbBrkb0wqHCIiIuJxqnciIiLicSocIiIi4nEqHCIiIuJxKhwiIiLicSocIiIi4nEqHCIiIuJxKhwiIiLicSocIiIi4nEqHCIiIuJxKhwiIiLicSocIiIi4nH/D4tlrOVpR8hbAAAAAElFTkSuQmCC" alt /></p>
<p>Note that the serialization logic produces <code>M2</code> but the
deserialization logic only sees <code>M2′</code>, without the class
author having to worry about how to produce it.</p>
<h2 data-number="1.4" id="soundness"><span class="header-section-number">1.4</span> Soundness<a href="#soundness" class="self-link"></a></h2>
<p>There are three approaches that are sound — that is, they avoid ODR
issues.</p>
<ol type="1">
<li>Subobject-wise serialization.</li>
<li>Subobject-wise serialization with an initial normalization
step.</li>
<li>Custom serialization with custom deserialization.</li>
</ol>
<p>Subobject-wise serialization alone (1) already gives us a tremendous
amount of value (since this gives us
<code class="sourceCode cpp">std<span class="op">::</span>tuple</code>,
<code class="sourceCode cpp">std<span class="op">::</span>optional</code>,
<code class="sourceCode cpp">std<span class="op">::</span>expected</code>,
<code class="sourceCode cpp">std<span class="op">::</span>variant</code>,
<code class="sourceCode cpp">std<span class="op">::</span>span</code>,
and <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>,
among many other types) while still being sound, but we really need
custom serialization/deserialization (3) to get the rest of the types
(the containers). Allowing normalization (2) helps a small number of
types avoid doing all the work that (3) would necessitate.</p>
<h2 data-number="1.5" id="original-design"><span class="header-section-number">1.5</span> Original Design<a href="#original-design" class="self-link"></a></h2>
<p>The <span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span> design was a custom
serialization/deserialization design. Given a class type
<code class="sourceCode cpp">C</code>:</p>
<ul>
<li>serialization was done by way of an <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span></code>
which had to return type <code class="sourceCode cpp">R</code>, which
had to be structural.</li>
<li>deserialization was done by way of a constructor from
<code class="sourceCode cpp">R</code>.</li>
</ul>
<p>This approach does satisfy the overall goal of avoiding ODR issues
(although the paper does not mention this at all), but the design had
some issues.</p>
<p>For one, it doesn’t cleanly support the case where we just want
member-wise template argument equivalence but our members happen to be
<code class="sourceCode cpp"><span class="kw">private</span></code> (the
<code class="sourceCode cpp">tuple</code>/<code class="sourceCode cpp">optional</code>/<code class="sourceCode cpp">variant</code>
cases). The paper tried to address this by allowing you to declare <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span></code>
as <em>defaulted</em>, which doesn’t really seem semantically equivalent
to the non-defaulted case. A defaulted copy constructor or comparison
operator <em>can</em> be written by hand, if tediously, but a defaulted
<code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
would require you duplicating the whole type just to copy it?</p>
<p>Another problem it doesn’t clearly support variable-length data. How
do we serialize <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>?
<code class="sourceCode cpp">std<span class="op">::</span>string</code>?
The <code class="sourceCode cpp">SmallString</code> class from earlier?
The paper kind of punted on this question, suggesting that maybe we just
make <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
a structural type by fiat since the language can just know what it
means. That’s not actually all that unreasonable, but it is a bit
unsatisfying.</p>
<p>But it’s at least not a bad start. There’s a lot to like about this
approach:</p>
<ul>
<li>it’s actually a fairly straightforward way to handle serialization
and deserialization, so it does get at the most desirable model for how
to extend support for class types as non-type template parameters</li>
<li>it can properly handle reference members — which must have their
template argument equivalence defined as the identity of the object
referred to, not its value</li>
<li>it prevents attempting to do the wrong thing with pointer
members.</li>
</ul>
<p>What I mean by the last point is: how do you define template argument
equivalence for <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>?
There’s really only one way to do it: as if it were a <code class="sourceCode cpp">std<span class="op">::</span>pair<span class="op">&lt;</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span>, <span class="dt">size_t</span><span class="op">&gt;</span></code>.
If you try to do it the other way (comparing the contents), you’ll run
into problems on the deserialization side:</p>
<div class="std">
<blockquote>
<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">class</span> string_view <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let&#39;s just simplify and ignore the template parameters</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> ptr_;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> len_;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// incorrect approach to serialization</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Repr <span class="op">{</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span> v; <span class="op">}</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> Repr <span class="op">{</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> Repr<span class="op">{.</span>v<span class="op">=</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;(</span>ptr_, ptr_ <span class="op">+</span> len_<span class="op">)}</span>;</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">// the only possible thing deserialization could do?</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> string_view<span class="op">(</span>Repr r<span class="op">)</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> ptr_<span class="op">(</span>r<span class="op">.</span>data<span class="op">())</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>        , len_<span class="op">(</span>r<span class="op">.</span>size<span class="op">())</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>If we serialize the <code class="sourceCode cpp">string_view</code>
as a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span></code>,
the only way to deserialize would be to refer to the contents of that
<code class="sourceCode cpp">vector</code>. Which immediately goes out
of scope, and the compiler can detect that.
<code class="sourceCode cpp">ptr_</code> has to be a permitted result of
a constant expression — basically that it has to point to something with
static storage duration. And the transient
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
allocation <em>is not</em> that. This error can be detected at compile
time.</p>
<p>And that will push you to having the <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
implementation for <code class="sourceCode cpp">string_view</code> be
just be defaulted — the correct implementation.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="reflection-will-fix-it"><span class="header-section-number">2</span>
Reflection Will Fix It<a href="#reflection-will-fix-it" class="self-link"></a></h1>
<p>One of the issues with the serialization problem that we had to deal
with was: how exactly do you serialize? What representation do you
return? And then how do you deserialize again? This was where we got
stuck with types like
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
(which needs variable-length representation) and even
<code class="sourceCode cpp">std<span class="op">::</span>tuple</code>
(which has a simple answer for serialization but you don’t want to just
create a whole new tuple type for this). Faisal Vali had the insight
that reflection provides a very easy answer for this question: you
serialize into (and then deserialize from) a range of <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>!</p>
<p>Let’s start with <code class="sourceCode cpp">SmallString</code>
again. We wanted to serialize just the objects in <code class="sourceCode cpp">data<span class="op">[</span><span class="dv">0</span><span class="op">:</span>length<span class="op">]</span></code>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> SmallString <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> data<span class="op">[</span><span class="dv">32</span><span class="op">]</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> length;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> repr;</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> length; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>            repr<span class="op">.</span>push_back<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>reflect_value<span class="op">(</span>data<span class="op">[</span>i<span class="op">]))</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> repr;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Here, we will return somewhere from 0 to 32 reflections of values of
type <code class="sourceCode cpp"><span class="dt">char</span></code>.
And then when we deserialize, we extract those values back:</p>
<div class="std">
<blockquote>
<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><span class="kw">class</span> SmallString <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// a tagged constructor to make overload resolution</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// easier to reason about</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> SmallString<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template_t,</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>                          std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> repr<span class="op">)</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> data<span class="op">()</span> <span class="co">// zero out the data first</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>        , length<span class="op">(</span>repr<span class="op">.</span>size<span class="op">())</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> length; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>            data<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> extract<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;(</span>repr<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>And this pattern works just as well for <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
which truly requires variable length contents:</p>
<div class="std">
<blockquote>
<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> T<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> vector <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    T<span class="op">*</span> begin_;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> size_;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> capacity_;</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Repr <span class="op">{</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">[]&gt;</span> p;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>        <span class="dt">size_t</span> n;</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">*</span> <span class="op">{</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> p<span class="op">.</span>get<span class="op">()</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">size_t</span> <span class="op">{</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> n;</span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> Repr <span class="op">{</span></span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> data <span class="op">=</span> std<span class="op">::</span>make_unique<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">[]&gt;(</span>size_<span class="op">)</span>;</span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> size_; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a>            data<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>reflect_value<span class="op">(</span>begin_<span class="op">[</span>i<span class="op">])</span>;</span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> Repr<span class="op">{</span></span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span>p<span class="op">=</span>std<span class="op">::</span>move<span class="op">(</span>data<span class="op">)</span>,</span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span>n<span class="op">=</span>size_,</span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> vector<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template_t,</span>
<span id="cb10-31"><a href="#cb10-31" aria-hidden="true" tabindex="-1"></a>                     Repr r<span class="op">)</span></span>
<span id="cb10-32"><a href="#cb10-32" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb10-33"><a href="#cb10-33" aria-hidden="true" tabindex="-1"></a>        begin_ <span class="op">=</span> std<span class="op">::</span>allocator<span class="op">&lt;</span>T<span class="op">&gt;::</span>allocate<span class="op">(</span>r<span class="op">.</span>size<span class="op">())</span>;</span>
<span id="cb10-34"><a href="#cb10-34" aria-hidden="true" tabindex="-1"></a>        size_ <span class="op">=</span> capacity_ <span class="op">=</span> r<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb10-35"><a href="#cb10-35" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> size_; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-36"><a href="#cb10-36" aria-hidden="true" tabindex="-1"></a>            <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>begin_ <span class="op">+</span> i<span class="op">)</span> T<span class="op">(</span>extract<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">.</span>p<span class="op">[</span>i<span class="op">]))</span>;</span>
<span id="cb10-37"><a href="#cb10-37" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb10-38"><a href="#cb10-38" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-39"><a href="#cb10-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>There are two additional points of interest in this example:</p>
<ol type="1">
<li><p>Note that here we’re using
<code class="sourceCode cpp">Repr</code> instead of <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>.
The compiler needs to understand what this return type is, but it
doesn’t <em>need</em> to be
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>.
Instead, we can take a page out of the design of <code class="sourceCode cpp"><span class="kw">static_assert</span></code> with
user-defined messages <span class="citation" data-cites="P2741R3">[<a href="https://wg21.link/p2741r3" role="doc-biblioref">P2741R3</a>]</span> — it doesn’t require
<code class="sourceCode cpp">std<span class="op">::</span>string</code>
specifically, just any type for which <code class="sourceCode cpp">M<span class="op">.</span>data<span class="op">()</span></code>
is convertible to <code class="sourceCode cpp"><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span></code>
and <code class="sourceCode cpp">M<span class="op">.</span>size<span class="op">()</span></code>
is convertible to
<code class="sourceCode cpp"><span class="dt">size_t</span></code>. We
could do the same, simply requiring that <code class="sourceCode cpp">R<span class="op">.</span>data<span class="op">()</span></code>
is convertible to <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">*</span></code>.</p></li>
<li><p>While this didn’t matter for
<code class="sourceCode cpp">SmallString</code>, here we are
round-tripping through <code class="sourceCode cpp">reflect_value</code>
and <code class="sourceCode cpp">extract</code> for arbitrary
(structural) <code class="sourceCode cpp">T</code>. This round-trip also
needs to do the custom serialization and deserialization for
<code class="sourceCode cpp">T</code> if that’s what the user wants, and
will happen automatically without the class author having to do
anything.</p></li>
</ol>
<p>The approach of serializing and deserializing through a contiguous
range of <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
is pretty nice. It definitely solves the problem, avoiding having to
special-case
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>.</p>
<p>But it’s not super convenient for some of the other types that we’ve
mentioned.</p>
<p>It’s… fine but not amazing for
<code class="sourceCode cpp">Optional</code>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Optional <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span> T value; <span class="op">}</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> engaged;</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Here, we don&#39;t need to use vector&lt;info&gt; since we know we have</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">// at most one value to represent and we already have a</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="co">// convenient answer for disengaged: the null reflection</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Repr <span class="op">{</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>meta<span class="op">::</span>info r;</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>        <span class="kw">explicit</span> <span class="kw">operator</span> <span class="dt">bool</span><span class="op">()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> r <span class="op">!=</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">()</span>;</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">*</span> <span class="op">{</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span> <span class="op">?</span> <span class="op">&amp;</span>r <span class="op">:</span> <span class="kw">nullptr</span>;</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">size_t</span> <span class="op">{</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span> <span class="op">?</span> <span class="dv">1</span> <span class="op">:</span> <span class="dv">0</span>;</span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> Repr <span class="op">{</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>engaged<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> Repr<span class="op">{.</span>r<span class="op">=</span>meta<span class="op">::</span>reflect_value<span class="op">(</span>value<span class="op">)}</span>;</span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> Repr<span class="op">{.</span>r<span class="op">=</span>meta<span class="op">::</span>info<span class="op">()}</span>;</span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Optional<span class="op">(</span>meta<span class="op">::</span>from_template_t, Repr repr<span class="op">)</span></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> engaged<span class="op">(</span>repr<span class="op">)</span></span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>engaged<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a>            <span class="op">::</span><span class="kw">new</span> <span class="op">(&amp;</span>value<span class="op">)</span> T<span class="op">(</span>extract<span class="op">&lt;</span>T<span class="op">&gt;(</span>repr<span class="op">.</span>r<span class="op">))</span>;</span>
<span id="cb11-37"><a href="#cb11-37" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-38"><a href="#cb11-38" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-39"><a href="#cb11-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>But it’s… really not the best for
<code class="sourceCode cpp">tuple</code>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">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="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Tuple <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// let&#39;s assume this syntax works (because the details are not important here)</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    Ts<span class="op">...</span> elems;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Note that here we&#39;re returning an array instead of a vector</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">// just to demonstrate that we can</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> array<span class="op">&lt;</span>meta<span class="op">::</span>info, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> <span class="op">{</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>        array<span class="op">&lt;</span>meta<span class="op">::</span>info, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> repr;</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>        <span class="dt">size_t</span> idx <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>        <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> mem <span class="op">:</span> nonstatic_data_members_of<span class="op">(^</span>Tuple<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>            <span class="co">// references and pointers have different rules for</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>            <span class="co">// template-argument-equivalence, and thus we need to</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>            <span class="co">// capture those differences... differently</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>            <span class="cf">if</span> <span class="op">(</span>type_is_reference<span class="op">(</span>type_of<span class="op">(</span>mem<span class="op">)))</span> <span class="op">{</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>                repr<span class="op">[</span>idx<span class="op">++]</span> <span class="op">=</span> reflect_object<span class="op">(</span><span class="kw">this</span><span class="op">-&gt;[:</span>mem<span class="op">:])</span>;</span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>                repr<span class="op">[</span>idx<span class="op">++]</span> <span class="op">=</span> reflect_value<span class="op">(</span><span class="kw">this</span><span class="op">-&gt;[:</span>mem<span class="op">:])</span>;</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> repr;</span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Tuple<span class="op">(</span>meta<span class="op">::</span>from_template_t tag,</span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a>                    array<span class="op">&lt;</span>meta<span class="op">::</span>info, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> repr<span class="op">)</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> Tuple<span class="op">(</span>tag, std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;()</span>, repr<span class="op">)</span></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-29"><a href="#cb12-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">size_t</span><span class="op">...</span> Is<span class="op">&gt;</span></span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Tuple<span class="op">(</span>meta<span class="op">::</span>from_template_t,</span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true" tabindex="-1"></a>                    index_sequence<span class="op">&lt;</span>Is<span class="op">...&gt;</span>,</span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true" tabindex="-1"></a>                    array<span class="op">&lt;</span>meta<span class="op">::</span>info, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> repr<span class="op">)</span></span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> elems<span class="op">(</span>extract<span class="op">&lt;</span>Ts<span class="op">&gt;(</span>repr<span class="op">[</span>Is<span class="op">]))...</span></span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Cool. This is… a lot. Not only is it a lot of decidedly non-trivial
code to write, it’s a lot of code that doesn’t really do all that much.
We’re <em>just</em> doing the default member-wise equivalence here. On
the one hand, it’s good that we <em>can</em> do this. But it’s not
really great that we <em>have to</em>. This is, after all, the
default.</p>
<p>One thing this suggests is that: if this is the default, we should be
able to say that it is the
<code class="sourceCode cpp"><span class="cf">default</span></code>:</p>
<div class="std">
<blockquote>
<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">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="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Tuple <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    Ts<span class="op">...</span> elems;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Tuple<span class="op">(</span>meta<span class="op">::</span>from_template_t, <span class="kw">auto</span> repr<span class="op">)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>I don’t like this for three reasons. First, we have to default two
different functions for what is effectively one operation that we’re
defaulting. Second, what actually does <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
return here? Third, while this makes the
<code class="sourceCode cpp">optional</code>,
<code class="sourceCode cpp">tuple</code>, and
<code class="sourceCode cpp">variant</code> implementations a lot
easier, it doesn’t help for those types that actually want to do some
normalization (like
<code class="sourceCode cpp">SmallString</code>).</p>
<p>But I think there’s still a good solution for this problem that
actually does solve all of these cases: allow <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
to return
<code class="sourceCode cpp"><span class="dt">void</span></code>!</p>
<p>That is: if <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
returns
<code class="sourceCode cpp"><span class="dt">void</span></code>, then
we still invoke the function — it might do normalization — but we’re
sticking with default member-wise serialization, which means that we
don’t need a custom deserialization function. In effect, an <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
returning
<code class="sourceCode cpp"><span class="dt">void</span></code> would
be the “opt in” that C++20 lacked for the case where you want
member-wise equivalence but have private members. This approach makes
the
<code class="sourceCode cpp">optional</code>/<code class="sourceCode cpp">tuple</code>/etc.
cases trivial:</p>
<div class="std">
<blockquote>
<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="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Optional <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span> T value; <span class="op">}</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> engaged;</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="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a></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">class</span> Tuple <span class="op">{</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    Ts<span class="op">...</span> elems;</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>While also making it very easy to implement the normalization
case:</p>
<div class="std">
<blockquote>
<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">class</span> SmallString <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> data<span class="op">[</span><span class="dv">32</span><span class="op">]</span>;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> length;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>fill<span class="op">(</span><span class="kw">this</span><span class="op">-&gt;</span>data <span class="op">+</span> <span class="kw">this</span><span class="op">-&gt;</span>length, <span class="kw">this</span><span class="op">-&gt;</span>data <span class="op">+</span> <span class="dv">32</span>, <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">)</span>;</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>The
<code class="sourceCode cpp"><span class="dt">void</span></code>-returning
case does at some complexity on top of the full
serialization-deserialization design, but it makes the opt-in for a
large amount of types a very sensible one-liner, so I think it’s worth
it.</p>
<h2 data-number="2.1" id="interesting-edge-case"><span class="header-section-number">2.1</span> Interesting Edge Case<a href="#interesting-edge-case" class="self-link"></a></h2>
<p>I wanted to show an interesting edge case. While the idea presented
here seems to solve all of the types I can reasonably think of — all the
standard library types mentioned here, both the simple ones
(<code class="sourceCode cpp">tuple</code>/<code class="sourceCode cpp">optional</code>/<code class="sourceCode cpp">variant</code>/etc)
and the containers — I can come up with an example that seems a little
awkward. Consider:</p>
<div class="std">
<blockquote>
<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">class</span> Fun <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> best; <span class="co">// within elems</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Today, this type isn’t structural because it has private members. But
in this case we don’t need to do anything special, just member-wise
equivalence, so it’s tempting to think that we can just do this:</p>
<div class="std">
<blockquote>
<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">class</span> Fun <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> best; <span class="co">// within elems</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>But… that’s not quite right. The rules I laid out above say that
after we invoke <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>,
we normalize all of the members. Which, for
<code class="sourceCode cpp">elems</code> is going to reallocate such
that <code class="sourceCode cpp">best</code> no longer points within
there. This should end up failing to compile because
<code class="sourceCode cpp">best</code> will not be a valid pointer
(for not pointing to persistent memory).</p>
<p>There are three ways I can think of to make this particular type
work.</p>
<p>The first is with a custom serialization, which we would do by
serializing the index rather than the pointer:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Fun <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> best; <span class="co">// within elems</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">{</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>meta<span class="op">::</span>reflect_value<span class="op">(</span>elems<span class="op">)</span>,</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>meta<span class="op">::</span>reflect_value<span class="op">(</span>best <span class="op">-</span> elems<span class="op">.</span>data<span class="op">())</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Fun<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template_t, std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> repr<span class="op">)</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> elems<span class="op">(</span>extract<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">*&gt;&gt;(</span>repr<span class="op">[</span><span class="dv">0</span><span class="op">]))</span></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>        , best<span class="op">(</span>extract<span class="op">&lt;</span><span class="dt">ptrdiff_t</span><span class="op">&gt;(</span>repr<span class="op">[</span><span class="dv">1</span><span class="op">])</span> <span class="op">+</span> elems<span class="op">.</span>data<span class="op">())</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>That works, but is annoying.</p>
<p>The second is to make the rules a bit more complicated and actually
allow this:</p>
<div class="std">
<blockquote>
<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">class</span> Fun <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> best; <span class="co">// within elems</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> delta <span class="op">=</span> best <span class="op">-</span> elems<span class="op">.</span>data<span class="op">()</span>;</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>        elems<span class="op">.</span><span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span>; <span class="co">// explicitly normalize</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>        best <span class="op">=</span> elems<span class="op">.</span>data<span class="op">()</span> <span class="op">+</span> delta;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>That is, here we <em>explicitly</em> normalize
<code class="sourceCode cpp">elems</code>, so the compiler will not
later <em>implicitly</em> normalize it. This obviously makes for a
simpler implementation of <code class="sourceCode cpp">Fun</code>, but
is it actually worth complicating the rules for? I don’t think so.</p>
<p>The last way is to change what we return. Right now, I’m just saying
that you can return any contiguous range of <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>.
In a way, that’s basically… type erasure. Sure, it’s type erasure that
we can’t get wrong (<code class="sourceCode cpp">extract</code> won’t
work if you provide the wrong type), but it’s still a bit surprising in
a strongly type language. So what if instead we allowed the original
<span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span> design:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Fun <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">*</span> best; <span class="co">// within elems</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Repr <span class="op">{</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> elems;</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>        <span class="dt">ptrdiff_t</span> index;</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">-&gt;</span> Repr <span class="op">{</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">{</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span>elems<span class="op">=</span>elems,</span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>            <span class="op">.</span>index<span class="op">=</span>best <span class="op">-</span> elems<span class="op">.</span>data<span class="op">()</span></span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> Fun<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template_t, Repr r<span class="op">)</span></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>        <span class="op">:</span> elems<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>r<span class="op">).</span>elems<span class="op">)</span></span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>        , best<span class="op">(</span>elems<span class="op">.</span>data<span class="op">()</span> <span class="op">+</span> r<span class="op">.</span>index<span class="op">)</span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This seems like a much better approach than the explicit
normalization one — but I’m still not sure it’s actually worth pursuing.
It doesn’t add too much complexity to the design (once we can return two
different kinds, is it really that big a deal to return three different
kinds?), but we should really only go this route if this is a
sufficiently common use-case. Which I’m not sure it is.</p>
<h2 data-number="2.2" id="alternate-spelling"><span class="header-section-number">2.2</span> Alternate Spelling<a href="#alternate-spelling" class="self-link"></a></h2>
<p>Following the principle that the way to spell the operator invoked in
the expression <code class="sourceCode cpp">c<span class="op">[</span>x<span class="op">]</span></code>
is <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">[]</span></code>,
an alternate spelling to the way to spell the operator invoked in the
<code class="sourceCode cpp"><em>type-id</em></code> <code class="sourceCode cpp">C<span class="op">&lt;</span>x<span class="op">&gt;</span></code>
could be <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;&gt;</span></code>
(instead of <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>).</p>
<p>Ultimately I prefer <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>,
simply because of the added searchability of using words instead of
punctuation, and this invocation will never appear in code, so there is
no added value of terseness.</p>
<h2 data-number="2.3" id="splitting"><span class="header-section-number">2.3</span> Splitting<a href="#splitting" class="self-link"></a></h2>
<p>There are two forms of this proposal:</p>
<ol type="1">
<li><code class="sourceCode cpp">T<span class="op">::</span><span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span></code>
returns a range of reflections and <code class="sourceCode cpp">T</code>
is constructible from that range,</li>
<li><code class="sourceCode cpp">T<span class="op">::</span><span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span></code>
returns
<code class="sourceCode cpp"><span class="dt">void</span></code>.</li>
</ol>
<p>The first form is the full round-trip custom
serialization/deserialization path that can support any type and is
essential for containers. The second is a purely convenience form for
simplicity, although one that covers a wide range of very common types
(like
<code class="sourceCode cpp">std<span class="op">::</span>tuple</code>,
<code class="sourceCode cpp">std<span class="op">::</span>optional</code>,
<code class="sourceCode cpp">std<span class="op">::</span>variant</code>,
<code class="sourceCode cpp">std<span class="op">::</span>string_view</code>,
<code class="sourceCode cpp">std<span class="op">::</span>span</code>,
etc.).</p>
<p>However, the first form also depends on reflection <span class="citation" data-cites="P2996R5">[<a href="https://wg21.link/p2996r5" role="doc-biblioref">P2996R5</a>]</span> and the latter does not. It is
possible to adopt purely the
<code class="sourceCode cpp"><span class="dt">void</span></code>-returning
form first with the understanding that we can later extend it to the
reflection-range-returning form. This immediately gives us support for
many useful types, and we can’t use types like <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
or
<code class="sourceCode cpp">std<span class="op">::</span>string</code>
as non-type template parameters yet anyway — not until we get
non-transient constexpr allocation (<span class="citation" data-cites="P1974R0">[<a href="https://wg21.link/p1974r0" role="doc-biblioref">P1974R0</a>]</span> <span class="citation" data-cites="P2670R1">[<a href="https://wg21.link/p2670r1" role="doc-biblioref">P2670R1</a>]</span>).</p>
<p>So it’s worth considering a reduced form of this proposal that is
simply the
<code class="sourceCode cpp"><span class="dt">void</span></code>-returning
form. This also has significantly less implementation complexity, since
it’s not a large extension over the existing rule.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">3</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>This proposal extends class types as non-type parameters as follows.
This isn’t exactly Core wording, but does contain something akin to
wording because I think that might be a clearer way to express the
idea.</p>
<h2 data-number="3.1" id="language"><span class="header-section-number">3.1</span> Language<a href="#language" class="self-link"></a></h2>
<p>First, as with <span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span>, I’m referring to <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
as a template representation function. A class type
<code class="sourceCode cpp">T</code> can provide an <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">template</span></code>
that must be
<code class="sourceCode cpp"><span class="kw">consteval</span></code>,
with one of two forms:</p>
<ol type="1">
<li>It returns
<code class="sourceCode cpp"><span class="dt">void</span></code>, in
which case every base class and non-static data member shall have
structural type and none of them shall be
<code class="sourceCode cpp"><span class="kw">mutable</span></code>.</li>
<li>It returns some value <code class="sourceCode cpp">R</code> such
that:
<ol type="a">
<li><code class="sourceCode cpp">R<span class="op">.</span>data<span class="op">()</span></code>
is convertible to <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">*</span></code>,
<code class="sourceCode cpp">R<span class="op">.</span>size<span class="op">()</span></code>
is convertible to
<code class="sourceCode cpp"><span class="dt">size_t</span></code>, and
<code class="sourceCode cpp"><span class="kw">static_cast</span><span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info <span class="kw">const</span><span class="op">*&gt;(</span>R<span class="op">.</span>data<span class="op">())[</span>i<span class="op">]</span></code>
shall be valid for all <code class="sourceCode cpp"><span class="dv">0</span> <span class="op">&lt;=</span> i <span class="op">&lt;</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">size_t</span><span class="op">&gt;(</span>R<span class="op">.</span>size<span class="op">())</span></code>,
and</li>
<li><code class="sourceCode cpp">T<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template, R<span class="op">)</span></code>
is a valid expression (where <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>from_template</code>
is a value of tag type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>from_template_t</code>).</li>
</ol></li>
</ol>
<p>As with <span class="citation" data-cites="P2484R0">[<a href="https://wg21.link/p2484r0" role="doc-biblioref">P2484R0</a>]</span>, I think I still want this
function to be non-user-invocable.</p>
<p>Second, we introduce the concept of template argument
normalization:</p>
<div class="std">
<blockquote>
<p>A value <code class="sourceCode cpp">v</code> of structural type
<code class="sourceCode cpp">T</code> is
<em>template-argument-normalized</em> as follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">1</a></span>
If <code class="sourceCode cpp">T</code> is a scalar type or an lvalue
reference type, nothing is done.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">2</a></span>
Otherwise, if <code class="sourceCode cpp">T</code> is an array type,
every element of the array is template-argument-normalized.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">3</a></span>
Otherwise (if <code class="sourceCode cpp">T</code> is a class type),
then
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(3.1)</a></span>
If <code class="sourceCode cpp">T</code> provides a template
representation function that returns
<code class="sourceCode cpp"><span class="dt">void</span></code>, then
that function is invoked on <code class="sourceCode cpp">v</code> and
then every subobject of <code class="sourceCode cpp">v</code> is
template-argument-normalized.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">(3.2)</a></span>
Otherwise, if <code class="sourceCode cpp">T</code> provides a template
representation function that returns a reflection range, then the new
value <code class="sourceCode cpp">T<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>from_template, v<span class="op">.</span><span class="kw">operator</span> <span class="kw">template</span><span class="op">())</span></code>
is used in place of <code class="sourceCode cpp">v</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">(3.3)</a></span>
Otherwise (if <code class="sourceCode cpp">T</code> does not provide a
template registration function), then every subobject of
<code class="sourceCode cpp">v</code> is
template-argument-normalized.</li>
</ul></li>
</ul>
</blockquote>
</div>
<p>Status quo so far is that <em>template-argument-normalization</em> is
a no-op for all types.</p>
<p>Third, we change the meaning of <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>reflect_value</code>
in <span class="citation" data-cites="P2996R5">[<a href="https://wg21.link/p2996r5" role="doc-biblioref">P2996R5</a>]</span> to perform
template-argument-normalization on its argument.</p>
<p>Fourth, we extend the definition of structural (here it’s either the
first bullet or both of the next two — the additional rules on template
registration functions will be covered in their own section):</p>
<div class="std">
<blockquote>
<p>A <em>structural type</em> is one of the following:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">(7.1)</a></span>
a scalar type, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">(7.2)</a></span>
an lvalue reference type, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">(7.2b)</a></span>
<span class="addu">an array type whose element type is structural,
or</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">(7.3)</a></span>
a literal class type with the following properties:
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">(7.3.0)</a></span>
<span class="addu">the class has an eligible template representation
function, or</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(7.3.1)</a></span>
all base classes and non-static data members are public and non-mutable
and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(7.3.2)</a></span>
the types of all bases classes and non-static data members are
structural types <span class="rm" style="color: #bf0303"><del>or
(possibly multidimensional) array thereof</del></span>.</li>
</ul></li>
</ul>
</blockquote>
</div>
<p>Fifth, we extend the definition of
<em>template-argument-equivalent</em> (note that two values of type
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
that represent values compare equal if those values are
template-argument-equivalent, so this definition is properly
recursive):</p>
<div class="std">
<blockquote>
<p>Two values are <em>template-argument-equivalent</em> if they are of
the same type and […]</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(2.11)</a></span>
they are of class type <span class="addu"><code class="sourceCode cpp">T</code></span> and</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(2.11.1)</a></span>
<span class="addu">If <code class="sourceCode cpp">T</code> has an
eligible template representation function that returns
non-<code class="sourceCode cpp"><span class="dt">void</span></code>,
then let <code class="sourceCode cpp">r1</code> and
<code class="sourceCode cpp">r2</code> be the results of invoking the
template registration function on the two values. The values are
considered template argument equivalent if <code class="sourceCode cpp">r1<span class="op">.</span>size<span class="op">()</span> <span class="op">==</span> r2<span class="op">.</span>size<span class="op">()</span></code>
and, for each <code class="sourceCode cpp">i</code> such that <code class="sourceCode cpp"><span class="dv">0</span> <span class="op">&lt;=</span> i <span class="op">&lt;</span> r1<span class="op">.</span>size<span class="op">()</span></code>,
<code class="sourceCode cpp">r1<span class="op">.</span>data<span class="op">()[</span>i<span class="op">]</span> <span class="op">==</span> r2<span class="op">.</span>data<span class="op">()[</span>i<span class="op">]</span></code>.</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">(2.11.2)</a></span>
<span class="addu">Otherwise, if</span> their corresponding direct
subobjects and reference members are template-argument-equivalent.</li>
</ul></li>
</ul>
</blockquote>
</div>
<p>Sixth, ensure that when initializing a non-type template parameter of
class type, that we perform template-argument-normalization (so that the
above rule on equivalence is only ever performed on normalized
values).</p>
<h2 data-number="3.2" id="library"><span class="header-section-number">3.2</span> Library<a href="#library" class="self-link"></a></h2>
<p>Add a new tag type, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>from_template_t</code>
and value of it named <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>from_template</code>.</p>
<p>Add a new type trait for <code class="sourceCode cpp">std<span class="op">::</span>is_structural</code>,
which we will need to provide constrained template registration
functions (a real use, as <span class="citation" data-cites="LWG3354">[<a href="https://wg21.link/lwg3354" role="doc-biblioref">LWG3354</a>]</span> requested).</p>
<p>Add a <code class="sourceCode cpp"><span class="kw">consteval</span> <span class="dt">void</span> <span class="kw">operator</span> <span class="kw">template</span><span class="op">()</span> <span class="op">{</span> <span class="op">}</span></code>
(that is, the default subobject-wise serialization with no
normalization) to all of the following library types, suitably
constrained:</p>
<ul>
<li><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>optional<span class="op">&lt;</span>T<span class="op">&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op">&lt;</span>T, E<span class="op">&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>variant<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>basic_string_view<span class="op">&lt;</span>CharT, Traits<span class="op">&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>span<span class="op">&lt;</span>T, Extent<span class="op">&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>chrono<span class="op">::</span>duration<span class="op">&lt;</span>Rep, Period<span class="op">&gt;</span></code></li>
<li><code class="sourceCode cpp">std<span class="op">::</span>chrono<span class="op">::</span>time_point<span class="op">&lt;</span>Clock, Duration<span class="op">&gt;</span></code></li>
</ul>
<p>There may need to be some wording similar to what we have for in <a href="http://eel.is/c++draft/pairs.pair#4">[pairs.pair]/4</a> right
now:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">4</a></span>
<code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>
is a structural type ([temp.param]) if
<code class="sourceCode cpp">T</code> and
<code class="sourceCode cpp">U</code> are both structural types. Two
values <code class="sourceCode cpp">p1</code> and
<code class="sourceCode cpp">p2</code> of type <code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>
are template-argument-equivalent ([temp.type]) if and only if
<code class="sourceCode cpp">p1<span class="op">.</span>first</code> and
<code class="sourceCode cpp">p2<span class="op">.</span>first</code> are
template-argument-equivalent and
<code class="sourceCode cpp">p1<span class="op">.</span>second</code>
and
<code class="sourceCode cpp">p2<span class="op">.</span>second</code>
are template-argument-equivalent.</p>
</blockquote>
</div>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="acknowledgements"><span class="header-section-number">4</span>
Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Richard Smith and Davis Herring for all the work in this
space. Thanks to Jeff Snyder for originally seeing how to solve this
problem (even if we didn’t end up using his original solution). Thanks
to Faisal Vali and Daveed Vandevoorde for working through a
solution.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">5</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-LWG3354" class="csl-entry" role="doc-biblioentry">
[LWG3354] Daniel Krügler. has_strong_structural_equality has a
meaningless definition. <a href="https://wg21.link/lwg3354"><div class="csl-block">https://wg21.link/lwg3354</div></a>
</div>
<div id="ref-P0732R2" class="csl-entry" role="doc-biblioentry">
[P0732R2] Jeff Snyder, Louis Dionne. 2018-06-06. Class Types in Non-Type
Template Parameters. <a href="https://wg21.link/p0732r2"><div class="csl-block">https://wg21.link/p0732r2</div></a>
</div>
<div id="ref-P1907R0" class="csl-entry" role="doc-biblioentry">
[P1907R0] Jens Maurer. 2019-10-07. Inconsistencies with non-type
template parameters. <a href="https://wg21.link/p1907r0"><div class="csl-block">https://wg21.link/p1907r0</div></a>
</div>
<div id="ref-P1907R1" class="csl-entry" role="doc-biblioentry">
[P1907R1] Jens Maurer. 2019-11-08. Inconsistencies with non-type
template parameters. <a href="https://wg21.link/p1907r1"><div class="csl-block">https://wg21.link/p1907r1</div></a>
</div>
<div id="ref-P1974R0" class="csl-entry" role="doc-biblioentry">
[P1974R0] Jeff Snyder, Louis Dionne, Daveed Vandevoorde. 2020-05-15.
Non-transient constexpr allocation using propconst. <a href="https://wg21.link/p1974r0"><div class="csl-block">https://wg21.link/p1974r0</div></a>
</div>
<div id="ref-P2484R0" class="csl-entry" role="doc-biblioentry">
[P2484R0] Richard Smith. 2021-11-17. Extending class types as non-type
template parameters. <a href="https://wg21.link/p2484r0"><div class="csl-block">https://wg21.link/p2484r0</div></a>
</div>
<div id="ref-P2670R1" class="csl-entry" role="doc-biblioentry">
[P2670R1] Barry Revzin. 2023-02-03. Non-transient constexpr allocation.
<a href="https://wg21.link/p2670r1"><div class="csl-block">https://wg21.link/p2670r1</div></a>
</div>
<div id="ref-P2741R3" class="csl-entry" role="doc-biblioentry">
[P2741R3] Corentin Jabot. 2023-06-16. user-generated static_assert
messages. <a href="https://wg21.link/p2741r3"><div class="csl-block">https://wg21.link/p2741r3</div></a>
</div>
<div id="ref-P2996R5" class="csl-entry" role="doc-biblioentry">
[P2996R5] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-08-14. Reflection for
C++26. <a href="https://wg21.link/p2996r5"><div class="csl-block">https://wg21.link/p2996r5</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
