<!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="2023-10-15" />
  <title>Reflection for C++26</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

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

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

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

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

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

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2996R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-10-15</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>
      Wyatt Childers<br>&lt;<a href="mailto:wcc@edg.com" class="email">wcc@edg.com</a>&gt;<br>
      Peter Dimov<br>&lt;<a href="mailto:pdimov@gmail.com" class="email">pdimov@gmail.com</a>&gt;<br>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
      Andrew Sutton<br>&lt;<a href="mailto:andrew.n.sutton@gmail.com" class="email">andrew.n.sutton@gmail.com</a>&gt;<br>
      Faisal Vali<br>&lt;<a href="mailto:faisalv@gmail.com" class="email">faisalv@gmail.com</a>&gt;<br>
      Daveed Vandevoorde<br>&lt;<a href="mailto:daveed@edg.com" class="email">daveed@edg.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"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="#notable-additions-to-p1240"><span class="toc-section-number">1.1</span> Notable Additions to P1240<span></span></a></li>
<li><a href="#why-a-single-opaque-reflection-type"><span class="toc-section-number">1.2</span> Why a single opaque reflection type?<span></span></a></li>
</ul></li>
<li><a href="#examples"><span class="toc-section-number">2</span> Examples<span></span></a>
<ul>
<li><a href="#back-and-forth"><span class="toc-section-number">2.1</span> Back-And-Forth<span></span></a></li>
<li><a href="#selecting-members"><span class="toc-section-number">2.2</span> Selecting Members<span></span></a></li>
<li><a href="#list-of-types-to-list-of-sizes"><span class="toc-section-number">2.3</span> List of Types to List of Sizes<span></span></a></li>
<li><a href="#implementing-make_integer_sequence"><span class="toc-section-number">2.4</span> Implementing <code class="sourceCode cpp">make_integer_sequence</code><span></span></a></li>
<li><a href="#getting-class-layout"><span class="toc-section-number">2.5</span> Getting Class Layout<span></span></a></li>
<li><a href="#enum-to-string"><span class="toc-section-number">2.6</span> Enum to String<span></span></a></li>
<li><a href="#parsing-command-line-options"><span class="toc-section-number">2.7</span> Parsing Command-Line Options<span></span></a></li>
<li><a href="#a-simple-tuple-type"><span class="toc-section-number">2.8</span> A Simple Tuple Type<span></span></a></li>
<li><a href="#struct-to-struct-of-arrays"><span class="toc-section-number">2.9</span> Struct to Struct of Arrays<span></span></a></li>
<li><a href="#parsing-command-line-options-ii"><span class="toc-section-number">2.10</span> Parsing Command-Line Options II<span></span></a></li>
<li><a href="#a-universal-formatter"><span class="toc-section-number">2.11</span> A Universal Formatter<span></span></a></li>
<li><a href="#implementing-member-wise-hash_append"><span class="toc-section-number">2.12</span> Implementing member-wise <code class="sourceCode cpp">hash_append</code><span></span></a></li>
<li><a href="#converting-a-struct-to-a-tuple"><span class="toc-section-number">2.13</span> Converting a Struct to a Tuple<span></span></a></li>
</ul></li>
<li><a href="#proposed-features"><span class="toc-section-number">3</span> Proposed Features<span></span></a>
<ul>
<li><a href="#the-reflection-operator"><span class="toc-section-number">3.1</span> The Reflection Operator (<code class="sourceCode cpp"><span class="op">^</span></code>)<span></span></a></li>
<li><a href="#splicers"><span class="toc-section-number">3.2</span> Splicers (<code class="sourceCode cpp"><span class="op">[:</span></code>…<code class="sourceCode cpp"><span class="op">:]</span></code>)<span></span></a>
<ul>
<li><a href="#range-splicers"><span class="toc-section-number">3.2.1</span> Range Splicers<span></span></a></li>
</ul></li>
<li><a href="#stdmetainfo"><span class="toc-section-number">3.3</span> <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code><span></span></a></li>
<li><a href="#metafunctions"><span class="toc-section-number">3.4</span> Metafunctions<span></span></a>
<ul>
<li><a href="#invalid_reflection-is_invalid-diagnose_error"><span class="toc-section-number">3.4.1</span> <code class="sourceCode cpp">invalid_reflection</code>, <code class="sourceCode cpp">is_invalid</code>, <code class="sourceCode cpp">diagnose_error</code><span></span></a></li>
<li><a href="#name_of-display_name_of-source_location_of"><span class="toc-section-number">3.4.2</span> <code class="sourceCode cpp">name_of</code>, <code class="sourceCode cpp">display_name_of</code>, <code class="sourceCode cpp">source_location_of</code><span></span></a></li>
<li><a href="#type_of-parent_of-entity_of"><span class="toc-section-number">3.4.3</span> <code class="sourceCode cpp">type_of</code>, <code class="sourceCode cpp">parent_of</code>, <code class="sourceCode cpp">entity_of</code><span></span></a></li>
<li><a href="#template_of-template_arguments_of"><span class="toc-section-number">3.4.4</span> <code class="sourceCode cpp">template_of</code>, <code class="sourceCode cpp">template_arguments_of</code><span></span></a></li>
<li><a href="#members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of"><span class="toc-section-number">3.4.5</span> <code class="sourceCode cpp">members_of</code>, <code class="sourceCode cpp">nonstatic_data_members_of</code>, <code class="sourceCode cpp">bases_of</code>, <code class="sourceCode cpp">enumerators_of</code>, <code class="sourceCode cpp">subobjects_of</code><span></span></a></li>
<li><a href="#substitute"><span class="toc-section-number">3.4.6</span> <code class="sourceCode cpp">substitute</code><span></span></a></li>
<li><a href="#entity_reft-value_oft-ptr_to_membert"><span class="toc-section-number">3.4.7</span> <code class="sourceCode cpp">entity_ref<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, <code class="sourceCode cpp">ptr_to_member<span class="op">&lt;</span>T<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#test_typepred"><span class="toc-section-number">3.4.8</span> <code class="sourceCode cpp">test_type<span class="op">&lt;</span>Pred<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#other-singular-reflection-predicates"><span class="toc-section-number">3.4.9</span> Other Singular Reflection Predicates<span></span></a></li>
<li><a href="#reflect_value"><span class="toc-section-number">3.4.10</span> <code class="sourceCode cpp">reflect_value</code><span></span></a></li>
<li><a href="#nsdm_description-synth_struct-synth_union"><span class="toc-section-number">3.4.11</span> <code class="sourceCode cpp">nsdm_description</code>, <code class="sourceCode cpp">synth_struct</code>, <code class="sourceCode cpp">synth_union</code><span></span></a></li>
<li><a href="#data-layout-reflection"><span class="toc-section-number">3.4.12</span> Data Layout Reflection<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">4</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>This is a proposal for a reduced initial set of features to support static reflection in C++. Specifically, we are mostly proposing a subset of features suggested in <span class="citation" data-cites="P1240R2">[<a href="#ref-P1240R2" role="doc-biblioref">P1240R2</a>]</span>:</p>
<ul>
<li>the representation of program elements via constant-expressions producing <em>reflection values</em> — <em>reflections</em> for short — of an opaque type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>,</li>
<li>a <em>reflection operator</em> (prefix <code class="sourceCode cpp"><span class="op">^</span></code>) that produces a reflection value for its operand construct,</li>
<li>a number of <code class="sourceCode cpp"><span class="kw">consteval</span></code> <em>metafunctions</em> to work with reflections (including deriving other reflections), and</li>
<li>constructs called <em>splicers</em> to produce grammatical elements from reflections (e.g., <code class="sourceCode cpp"><span class="op">[:</span> <em>refl</em> <span class="op">:]</span></code>).</li>
</ul>
<p>This proposal is not intended to be the end-game as far as reflection and compile-time metaprogramming are concerned. Instead, we expect it will be a useful core around which more powerful features will be added incrementally over time. In particular, we believe that most or all the remaining features explored in P1240R2 and that code injection (along the lines described in <span class="citation" data-cites="P2237R0">[<a href="#ref-P2237R0" role="doc-biblioref">P2237R0</a>]</span>) are desirable directions to pursue.</p>
<p>Our choice to start with something smaller is primarily motivated by the belief that that improves the chances of these facilities making it into the language sooner rather than later.</p>
<h2 data-number="1.1" id="notable-additions-to-p1240"><span class="header-section-number">1.1</span> Notable Additions to P1240<a href="#notable-additions-to-p1240" class="self-link"></a></h2>
<p>While we tried to select a useful subset of the P1240 features, we also made a few additions and changes. Most of those changes are minor. For example, we added a <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>test_type</code> interface that makes it convenient to use existing standard type predicates (such as <code class="sourceCode cpp">is_class_v</code>) in reflection computations.</p>
<p>One addition does stand out, however: We have added metafunctions that permit the synthesis of simple struct and union types. While it is not nearly as powerful as generalized code injection (see <span class="citation" data-cites="P2237R0">[<a href="#ref-P2237R0" role="doc-biblioref">P2237R0</a>]</span>), it can be remarkably effective in practice.</p>
<h2 data-number="1.2" id="why-a-single-opaque-reflection-type"><span class="header-section-number">1.2</span> Why a single opaque reflection type?<a href="#why-a-single-opaque-reflection-type" class="self-link"></a></h2>
<p>Perhaps the most common suggestion made regarding the framework outlined in P1240 is to switch from the single <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> type to a family of types covering various language elements (e.g., <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>variable</code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>type</code>, etc.).</p>
<p>We believe that doing so would be mistake with very serious consequences for the future of C++.</p>
<p>Specifically, it would codify the language design into the type system. We know from experience that it has been quasi-impossible to change the semantics of standard types once they were standardized, and there is no reason to think that such evolution would become easier in the future. Suppose for example that we had standardized a reflection type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>variable</code> in C++03 to represent what the standard called “variables” at the time. In C++11, the term “variable” was extended to include “references”. Such an change would have been difficult to do given that C++ by then likely would have had plenty of code that depended on a type arrangement around the more restricted definition of “variable”. That scenario is clearly backward-looking, but there is no reason to believe that similar changes might not be wanted in the future and we strongly believe that it behooves us to avoid adding undue constraints on the evolution of the language.</p>
<p>Other advantages of a single opaque type include:</p>
<ul>
<li>it makes no assumptions about the representation used within the implementation (e.g., it doesn’t advantage one compiler over another),</li>
<li>it is trivially extensible (no types need to be added to represent additional language elements and meta-elements as the language evolves), and</li>
<li>it allows convenient collections of heterogeneous constructs without having to surface reference semantics (e.g., a <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> can easily represent a mixed template argument list — containing types and nontypes — without fear of slicing values).</li>
</ul>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="examples"><span class="header-section-number">2</span> Examples<a href="#examples" class="self-link"></a></h1>
<p>We start with a number of examples that show off what is possible with the proposed set of features. It is expected that these are mostly self-explanatory. Read ahead to the next sections for a more systematic description of each element of this proposal.</p>
<p>A number of our examples here show a few other language features that we hope to progress at the same time. This facility does not strictly rely on these features, and it is possible to do without them - but it would greatly help the usability experience if those could be adopted as well:</p>
<ul>
<li>expansion statements <span class="citation" data-cites="P1306R1">[<a href="#ref-P1306R1" role="doc-biblioref">P1306R1</a>]</span></li>
<li>non-transient constexpr allocation <span class="citation" data-cites="P0784R7">[<a href="#ref-P0784R7" role="doc-biblioref">P0784R7</a>]</span> <span class="citation" data-cites="P1974R0">[<a href="#ref-P1974R0" role="doc-biblioref">P1974R0</a>]</span> <span class="citation" data-cites="P2670R1">[<a href="#ref-P2670R1" role="doc-biblioref">P2670R1</a>]</span></li>
</ul>
<h2 data-number="2.1" id="back-and-forth"><span class="header-section-number">2.1</span> Back-And-Forth<a href="#back-and-forth" class="self-link"></a></h2>
<p>Our first example is not meant to be compelling but to show how to go back and forth between the reflection domain and the grammatical domain:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> <span class="op">^</span><span class="dt">int</span>;</span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">typename</span><span class="op">[:</span>r<span class="op">:]</span> x <span class="op">=</span> <span class="dv">42</span>;       <span class="co">// Same as: int x = 42;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="kw">typename</span><span class="op">[:^</span><span class="dt">char</span><span class="op">:]</span> c <span class="op">=</span> <span class="ch">&#39;*&#39;</span>;  <span class="co">// Same as: char c = &#39;*&#39;;</span></span></code></pre></div>
</blockquote>
<p>The <code class="sourceCode cpp"><span class="kw">typename</span></code> prefix can be omitted in the same contexts as with dependent qualified names. For example:</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">using</span> MyType <span class="op">=</span> <span class="op">[:</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)&lt;</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">long</span><span class="op">)?</span> <span class="op">^</span><span class="dt">long</span> <span class="op">:</span> <span class="op">^</span><span class="dt">int</span><span class="op">:]</span>;  <span class="co">// Implicit &quot;typename&quot; prefix.</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.2" id="selecting-members"><span class="header-section-number">2.2</span> Selecting Members<a href="#selecting-members" class="self-link"></a></h2>
<p>Our second example enables selecting a member “by number” for a specific type. It also shows the use of a metafunction dealing with diagnostics:</p>
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">struct</span> S <span class="op">{</span> <span class="dt">unsigned</span> i<span class="op">:</span><span class="dv">2</span>, j<span class="op">:</span><span class="dv">6</span>; <span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="kw">consteval</span> <span class="kw">auto</span> member_number<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4"></a>  <span class="cf">if</span> <span class="op">(</span>n <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="cf">return</span> <span class="op">^</span>S<span class="op">::</span>i;</span>
<span id="cb3-5"><a href="#cb3-5"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>n <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="cf">return</span> <span class="op">^</span>S<span class="op">::</span>j;</span>
<span id="cb3-6"><a href="#cb3-6"></a>  <span class="cf">else</span> <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>invalid_reflection<span class="op">(</span><span class="st">&quot;Only field numbers 0 and 1 permitted&quot;</span><span class="op">)</span>;</span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="op">}</span></span>
<span id="cb3-8"><a href="#cb3-8"></a></span>
<span id="cb3-9"><a href="#cb3-9"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>  S s<span class="op">{</span><span class="dv">0</span>, <span class="dv">0</span><span class="op">}</span>;</span>
<span id="cb3-11"><a href="#cb3-11"></a>  s<span class="op">.[:</span>member_number<span class="op">(</span><span class="dv">1</span><span class="op">):]</span> <span class="op">=</span> <span class="dv">42</span>;  <span class="co">// Same as: s.j = 42;</span></span>
<span id="cb3-12"><a href="#cb3-12"></a>  s<span class="op">.[:</span>member_number<span class="op">(</span><span class="dv">5</span><span class="op">):]</span> <span class="op">=</span> <span class="dv">0</span>;   <span class="co">// Error (likely with &quot;Only field numbers 0 and 1 permitted&quot; in text).</span></span>
<span id="cb3-13"><a href="#cb3-13"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This example also illustrates that bit fields are not beyond the reach of this proposal.</p>
<h2 data-number="2.3" id="list-of-types-to-list-of-sizes"><span class="header-section-number">2.3</span> List of Types to List of Sizes<a href="#list-of-types-to-list-of-sizes" class="self-link"></a></h2>
<p>Here, <code class="sourceCode cpp">sizes</code> will be a <code class="sourceCode cpp">std<span class="op">::</span>array<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span>, <span class="dv">3</span><span class="op">&gt;</span></code> initialized with <code class="sourceCode cpp"><span class="op">{</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)</span>, <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>, <span class="kw">sizeof</span><span class="op">(</span><span class="dt">double</span><span class="op">)}</span></code>:</p>
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>array types <span class="op">=</span> <span class="op">{^</span><span class="dt">int</span>, <span class="op">^</span><span class="dt">float</span>, <span class="op">^</span><span class="dt">double</span><span class="op">}</span>;</span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw">constexpr</span> std<span class="op">::</span>array sizes <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a>  std<span class="op">::</span>array<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span>, types<span class="op">.</span>size<span class="op">()&gt;</span> r;</span>
<span id="cb4-4"><a href="#cb4-4"></a>  std<span class="op">::</span>ranges<span class="op">::</span>transform<span class="op">(</span>types, r<span class="op">.</span>begin<span class="op">()</span>, std<span class="op">::</span>meta<span class="op">::</span>size_of<span class="op">)</span>;</span>
<span id="cb4-5"><a href="#cb4-5"></a>  <span class="cf">return</span> r;</span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="op">}()</span>;</span></code></pre></div>
</blockquote>
<p>Compare this to the following type-based approach, which produces the same array <code class="sourceCode cpp">sizes</code>:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...&gt;</span> <span class="kw">struct</span> list <span class="op">{}</span>;</span>
<span id="cb5-2"><a href="#cb5-2"></a></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="kw">using</span> types <span class="op">=</span> list<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">float</span>, <span class="dt">double</span><span class="op">&gt;</span>;</span>
<span id="cb5-4"><a href="#cb5-4"></a></span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="kw">constexpr</span> <span class="kw">auto</span> sizes <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...&gt;</span> <span class="kw">class</span> L, <span class="kw">class</span><span class="op">...</span> T<span class="op">&gt;(</span>L<span class="op">&lt;</span>T<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6"></a>    <span class="cf">return</span> std<span class="op">::</span>array<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span>, <span class="kw">sizeof</span><span class="op">...(</span>T<span class="op">)&gt;{{</span> <span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)...</span> <span class="op">}}</span>;</span>
<span id="cb5-7"><a href="#cb5-7"></a><span class="op">}(</span>types<span class="op">{})</span>;</span></code></pre></div>
</blockquote>
<h2 data-number="2.4" id="implementing-make_integer_sequence"><span class="header-section-number">2.4</span> Implementing <code class="sourceCode cpp">make_integer_sequence</code><a href="#implementing-make_integer_sequence" class="self-link"></a></h2>
<p>We can provide a better implementation of <code class="sourceCode cpp">make_integer_sequence</code> than a hand-rolled approach using regular template metaprogramming (although standard libraries today rely on an intrinsic for this):</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="pp">#include </span><span class="im">&lt;utility&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a></span>
<span id="cb6-4"><a href="#cb6-4"></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="cb6-5"><a href="#cb6-5"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info make_integer_seq_refl<span class="op">(</span>T N<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-6"><a href="#cb6-6"></a>  std<span class="op">::</span>vector args<span class="op">{^</span>T<span class="op">}</span>;</span>
<span id="cb6-7"><a href="#cb6-7"></a>  <span class="cf">for</span> <span class="op">(</span>T k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> N; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-8"><a href="#cb6-8"></a>    args<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>k<span class="op">))</span>;</span>
<span id="cb6-9"><a href="#cb6-9"></a>  <span class="op">}</span></span>
<span id="cb6-10"><a href="#cb6-10"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>std<span class="op">::</span>integer_sequence, args<span class="op">)</span>;</span>
<span id="cb6-11"><a href="#cb6-11"></a><span class="op">}</span></span>
<span id="cb6-12"><a href="#cb6-12"></a></span>
<span id="cb6-13"><a href="#cb6-13"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, T N<span class="op">&gt;</span></span>
<span id="cb6-14"><a href="#cb6-14"></a>  <span class="kw">using</span> make_integer_sequence <span class="op">=</span> <span class="op">[:</span>make_integer_seq_refl<span class="op">&lt;</span>T<span class="op">&gt;(</span>N<span class="op">):]</span>;</span></code></pre></div>
</blockquote>
<h2 data-number="2.5" id="getting-class-layout"><span class="header-section-number">2.5</span> Getting Class Layout<a href="#getting-class-layout" class="self-link"></a></h2>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">struct</span> member_descriptor</span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3"></a>  std<span class="op">::</span><span class="dt">size_t</span> offset;</span>
<span id="cb7-4"><a href="#cb7-4"></a>  std<span class="op">::</span><span class="dt">size_t</span> size;</span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="op">}</span>;</span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a><span class="co">// returns std::array&lt;member_descriptor, N&gt;</span></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> S<span class="op">&gt;</span></span>
<span id="cb7-9"><a href="#cb7-9"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_layout<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-10"><a href="#cb7-10"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>S<span class="op">)</span>;</span>
<span id="cb7-11"><a href="#cb7-11"></a>  std<span class="op">::</span>array<span class="op">&lt;</span>member_descriptor, members<span class="op">.</span>size<span class="op">()&gt;</span> layout;</span>
<span id="cb7-12"><a href="#cb7-12"></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> members<span class="op">.</span>size<span class="op">()</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-13"><a href="#cb7-13"></a>      layout<span class="op">[</span>i<span class="op">]</span> <span class="op">=</span> <span class="op">{.</span>offset<span class="op">=</span>offset_of<span class="op">(</span>members<span class="op">[</span>i<span class="op">])</span>, <span class="op">.</span>size<span class="op">=</span>size_of<span class="op">(</span>members<span class="op">[</span>i<span class="op">])}</span>;</span>
<span id="cb7-14"><a href="#cb7-14"></a>  <span class="op">}</span></span>
<span id="cb7-15"><a href="#cb7-15"></a>  <span class="cf">return</span> layout;</span>
<span id="cb7-16"><a href="#cb7-16"></a><span class="op">}</span></span>
<span id="cb7-17"><a href="#cb7-17"></a></span>
<span id="cb7-18"><a href="#cb7-18"></a><span class="kw">struct</span> X</span>
<span id="cb7-19"><a href="#cb7-19"></a><span class="op">{</span></span>
<span id="cb7-20"><a href="#cb7-20"></a>    <span class="dt">char</span> a;</span>
<span id="cb7-21"><a href="#cb7-21"></a>    <span class="dt">int</span> b;</span>
<span id="cb7-22"><a href="#cb7-22"></a>    <span class="dt">double</span> c;</span>
<span id="cb7-23"><a href="#cb7-23"></a><span class="op">}</span>;</span>
<span id="cb7-24"><a href="#cb7-24"></a></span>
<span id="cb7-25"><a href="#cb7-25"></a><span class="co">/*constexpr*/</span> <span class="kw">auto</span> Xd <span class="op">=</span> get_layout<span class="op">&lt;</span>X<span class="op">&gt;()</span>;</span>
<span id="cb7-26"><a href="#cb7-26"></a></span>
<span id="cb7-27"><a href="#cb7-27"></a><span class="co">/*</span></span>
<span id="cb7-28"><a href="#cb7-28"></a><span class="co">where Xd would be std::array&lt;member_descriptor, 3&gt;{{</span></span>
<span id="cb7-29"><a href="#cb7-29"></a><span class="co">  { 0, 1 }, { 4, 4 }, { 8, 8 }</span></span>
<span id="cb7-30"><a href="#cb7-30"></a><span class="co">}}</span></span>
<span id="cb7-31"><a href="#cb7-31"></a><span class="co">*/</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.6" id="enum-to-string"><span class="header-section-number">2.6</span> Enum to String<a href="#enum-to-string" class="self-link"></a></h2>
<p>One of the most commonly requested facilities is to convert an enum value to a string (this example relies on expansion statements):</p>
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>  <span class="kw">requires</span> std<span class="op">::</span>is_enum_v<span class="op">&lt;</span>E<span class="op">&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="kw">constexpr</span> std<span class="op">::</span>string enum_to_string<span class="op">(</span>E value<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-4"><a href="#cb8-4"></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> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
<span id="cb8-5"><a href="#cb8-5"></a>    <span class="cf">if</span> <span class="op">(</span>value <span class="op">==</span> <span class="op">[:</span>e<span class="op">:])</span> <span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6"></a>      <span class="cf">return</span> std<span class="op">::</span>string<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb8-7"><a href="#cb8-7"></a>    <span class="op">}</span></span>
<span id="cb8-8"><a href="#cb8-8"></a>  <span class="op">}</span></span>
<span id="cb8-9"><a href="#cb8-9"></a></span>
<span id="cb8-10"><a href="#cb8-10"></a>  <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a><span class="op">}</span></span>
<span id="cb8-12"><a href="#cb8-12"></a></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="kw">enum</span> Color <span class="op">{</span> red, green, blue <span class="op">}</span>;</span>
<span id="cb8-14"><a href="#cb8-14"></a><span class="kw">static_assert</span><span class="op">(</span>enum_to_string<span class="op">(</span>Color<span class="op">::</span>red<span class="op">)</span> <span class="op">==</span> <span class="st">&quot;red&quot;</span><span class="op">)</span>;</span>
<span id="cb8-15"><a href="#cb8-15"></a><span class="kw">static_assert</span><span class="op">(</span>enum_to_string<span class="op">(</span>Color<span class="op">(</span><span class="dv">42</span><span class="op">))</span> <span class="op">==</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>We can also do the reverse in pretty much the same way:</p>
<blockquote>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2"></a>  <span class="kw">requires</span> std<span class="op">::</span>is_enum_v<span class="op">&lt;</span>E<span class="op">&gt;</span></span>
<span id="cb9-3"><a href="#cb9-3"></a><span class="kw">constexpr</span> std<span class="op">::</span>optional<span class="op">&lt;</span>E<span class="op">&gt;</span> string_to_enum<span class="op">(</span>std<span class="op">::</span>string_view name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-4"><a href="#cb9-4"></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> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
<span id="cb9-5"><a href="#cb9-5"></a>    <span class="cf">if</span> <span class="op">(</span>name <span class="op">==</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">))</span> <span class="op">{</span></span>
<span id="cb9-6"><a href="#cb9-6"></a>      <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>;</span>
<span id="cb9-7"><a href="#cb9-7"></a>    <span class="op">}</span></span>
<span id="cb9-8"><a href="#cb9-8"></a>  <span class="op">}</span></span>
<span id="cb9-9"><a href="#cb9-9"></a></span>
<span id="cb9-10"><a href="#cb9-10"></a>  <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb9-11"><a href="#cb9-11"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>But we don’t have to use expansion statements - we can also use algorithms. For instance, <code class="sourceCode cpp">enum_to_string</code> can also be implemented this way (this example relies on non-transient constexpr allocation):</p>
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a>  <span class="kw">requires</span> std<span class="op">::</span>is_enum_v<span class="op">&lt;</span>E<span class="op">&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3"></a><span class="kw">constexpr</span> std<span class="op">::</span>string enum_to_string<span class="op">(</span>E value<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> enumerators <span class="op">=</span></span>
<span id="cb10-5"><a href="#cb10-5"></a>    std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>E<span class="op">)</span></span>
<span id="cb10-6"><a href="#cb10-6"></a>    <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span>std<span class="op">::</span>meta<span class="op">::</span>info e<span class="op">){</span></span>
<span id="cb10-7"><a href="#cb10-7"></a>        <span class="cf">return</span> std<span class="op">::</span>pair<span class="op">&lt;</span>E, std<span class="op">::</span>string<span class="op">&gt;(</span>std<span class="op">::</span>meta<span class="op">::</span>value_of<span class="op">&lt;</span>E<span class="op">&gt;(</span>e<span class="op">)</span>, std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb10-8"><a href="#cb10-8"></a>      <span class="op">})</span></span>
<span id="cb10-9"><a href="#cb10-9"></a>    <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>to<span class="op">&lt;</span>std<span class="op">::</span>map<span class="op">&gt;()</span>;</span>
<span id="cb10-10"><a href="#cb10-10"></a></span>
<span id="cb10-11"><a href="#cb10-11"></a>  <span class="kw">auto</span> it <span class="op">=</span> enumerators<span class="op">.</span>find<span class="op">(</span>value<span class="op">)</span>;</span>
<span id="cb10-12"><a href="#cb10-12"></a>  <span class="cf">if</span> <span class="op">(</span>it <span class="op">!=</span> enumerators<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb10-13"><a href="#cb10-13"></a>    <span class="cf">return</span> it<span class="op">-&gt;</span>second;</span>
<span id="cb10-14"><a href="#cb10-14"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb10-15"><a href="#cb10-15"></a>    <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb10-16"><a href="#cb10-16"></a>  <span class="op">}</span></span>
<span id="cb10-17"><a href="#cb10-17"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Note that this last version has lower complexity: While the versions using an expansion statement use an expected O(N) number of comparisons to find the matching entry, a <code class="sourceCode cpp">std<span class="op">::</span>map</code> achieves the same with O(log(N)) complexity (where N is the number of enumerator constants).</p>
<h2 data-number="2.7" id="parsing-command-line-options"><span class="header-section-number">2.7</span> Parsing Command-Line Options<a href="#parsing-command-line-options" class="self-link"></a></h2>
<p>Our next example shows how a command-line option parser could work by automatically inferring flags based on member names. A real command-line parser would of course be more complex, this is just the beginning:</p>
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> Opts<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a><span class="kw">auto</span> parse_options<span class="op">(</span>std<span class="op">::</span>span<span class="op">&lt;</span>std<span class="op">::</span>string_view <span class="kw">const</span><span class="op">&gt;</span> args<span class="op">)</span> <span class="op">-&gt;</span> Opts <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3"></a>  Opts opts;</span>
<span id="cb11-4"><a href="#cb11-4"></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> dm <span class="op">:</span> nonstatic_data_members_of<span class="op">(^</span>Opts<span class="op">))</span> <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5"></a>    <span class="kw">auto</span> it <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>find_if<span class="op">(</span>args,</span>
<span id="cb11-6"><a href="#cb11-6"></a>      <span class="op">[](</span>std<span class="op">::</span>string_view arg<span class="op">){</span></span>
<span id="cb11-7"><a href="#cb11-7"></a>        <span class="cf">return</span> args<span class="op">.</span>starts_with<span class="op">(</span><span class="st">&quot;--&quot;</span><span class="op">)</span> <span class="op">&amp;&amp;</span> args<span class="op">.</span>substr<span class="op">(</span><span class="dv">2</span><span class="op">)</span> <span class="op">==</span> name_of<span class="op">(</span>dm<span class="op">)</span>;</span>
<span id="cb11-8"><a href="#cb11-8"></a>      <span class="op">})</span>;</span>
<span id="cb11-9"><a href="#cb11-9"></a></span>
<span id="cb11-10"><a href="#cb11-10"></a>    <span class="cf">if</span> <span class="op">(</span>it <span class="op">==</span> args<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb11-11"><a href="#cb11-11"></a>      <span class="co">// no option provided, use default</span></span>
<span id="cb11-12"><a href="#cb11-12"></a>      <span class="cf">continue</span>;</span>
<span id="cb11-13"><a href="#cb11-13"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>it <span class="op">+</span> <span class="dv">1</span> <span class="op">==</span> args<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb11-14"><a href="#cb11-14"></a>      std<span class="op">::</span>print<span class="op">(</span>stderr, <span class="st">&quot;Option {} is missing a value</span><span class="sc">\n</span><span class="st">&quot;</span>, <span class="op">*</span>it<span class="op">)</span>;</span>
<span id="cb11-15"><a href="#cb11-15"></a>      std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb11-16"><a href="#cb11-16"></a>    <span class="op">}</span></span>
<span id="cb11-17"><a href="#cb11-17"></a></span>
<span id="cb11-18"><a href="#cb11-18"></a>    <span class="kw">using</span> T <span class="op">=</span> <span class="kw">typename</span><span class="op">[:</span>type_of<span class="op">(</span>dm<span class="op">):]</span>;</span>
<span id="cb11-19"><a href="#cb11-19"></a>    <span class="kw">auto</span> iss <span class="op">=</span> ispanstream<span class="op">(</span>it<span class="op">[</span><span class="dv">1</span><span class="op">])</span>;</span>
<span id="cb11-20"><a href="#cb11-20"></a>    <span class="cf">if</span> <span class="op">(</span>iss <span class="op">&gt;&gt;</span> opts<span class="op">.[:</span>dm<span class="op">:]</span>; <span class="op">!</span>iss<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-21"><a href="#cb11-21"></a>      std<span class="op">::</span>print<span class="op">(</span>stderr, <span class="st">&quot;Failed to parse option {} into a {}</span><span class="sc">\n</span><span class="st">&quot;</span>, <span class="op">*</span>it, display_name_of<span class="op">(^</span>T<span class="op">))</span>;</span>
<span id="cb11-22"><a href="#cb11-22"></a>      std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb11-23"><a href="#cb11-23"></a>    <span class="op">}</span></span>
<span id="cb11-24"><a href="#cb11-24"></a>  <span class="op">}</span></span>
<span id="cb11-25"><a href="#cb11-25"></a>  <span class="cf">return</span> opts;</span>
<span id="cb11-26"><a href="#cb11-26"></a><span class="op">}</span></span>
<span id="cb11-27"><a href="#cb11-27"></a></span>
<span id="cb11-28"><a href="#cb11-28"></a><span class="kw">struct</span> MyOpts <span class="op">{</span></span>
<span id="cb11-29"><a href="#cb11-29"></a>  string file_name <span class="op">=</span> <span class="st">&quot;input.txt&quot;</span>;  <span class="co">// Option &quot;--file_name &lt;string&gt;&quot;</span></span>
<span id="cb11-30"><a href="#cb11-30"></a>  <span class="dt">int</span>    count <span class="op">=</span> <span class="dv">1</span>;                <span class="co">// Option &quot;--count &lt;int&gt;&quot;</span></span>
<span id="cb11-31"><a href="#cb11-31"></a><span class="op">}</span>;</span>
<span id="cb11-32"><a href="#cb11-32"></a></span>
<span id="cb11-33"><a href="#cb11-33"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc, <span class="dt">char</span> <span class="op">*</span>argv<span class="op">[])</span> <span class="op">{</span></span>
<span id="cb11-34"><a href="#cb11-34"></a>  MyOpts opts <span class="op">=</span> parse_options<span class="op">&lt;</span>MyOpts<span class="op">&gt;(</span>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string_view<span class="op">&gt;(</span>argv<span class="op">+</span><span class="dv">1</span>, argv<span class="op">+</span>argc<span class="op">))</span>;</span>
<span id="cb11-35"><a href="#cb11-35"></a>  <span class="co">// ...</span></span>
<span id="cb11-36"><a href="#cb11-36"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>(This example is based on a presentation by Matúš Chochlík.)</p>
<h2 data-number="2.8" id="a-simple-tuple-type"><span class="header-section-number">2.8</span> A Simple Tuple Type<a href="#a-simple-tuple-type" class="self-link"></a></h2>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2"></a></span>
<span id="cb12-3"><a href="#cb12-3"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span> <span class="kw">struct</span> Tuple <span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4"></a>  <span class="kw">using</span> storage <span class="op">=</span> <span class="kw">typename</span><span class="op">[:</span>std<span class="op">::</span>meta<span class="op">::</span>synth_struct<span class="op">({</span>nsdm_description<span class="op">(^</span>T<span class="op">)...}):]</span>;</span>
<span id="cb12-5"><a href="#cb12-5"></a>  storage data;</span>
<span id="cb12-6"><a href="#cb12-6"></a></span>
<span id="cb12-7"><a href="#cb12-7"></a>  Tuple<span class="op">():</span> data<span class="op">{}</span> <span class="op">{}</span></span>
<span id="cb12-8"><a href="#cb12-8"></a>  Tuple<span class="op">(</span>Ts <span class="kw">const</span><span class="op">&amp;</span> <span class="op">...</span>vs<span class="op">):</span> data<span class="op">{</span> vs<span class="op">...</span> <span class="op">}</span> <span class="op">{}</span></span>
<span id="cb12-9"><a href="#cb12-9"></a><span class="op">}</span>;</span>
<span id="cb12-10"><a href="#cb12-10"></a></span>
<span id="cb12-11"><a href="#cb12-11"></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-12"><a href="#cb12-12"></a>  <span class="kw">struct</span> std<span class="op">::</span>tuple_size<span class="op">&lt;</span>Tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;:</span> <span class="kw">public</span> integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> <span class="op">{}</span>;</span>
<span id="cb12-13"><a href="#cb12-13"></a></span>
<span id="cb12-14"><a href="#cb12-14"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> I, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb12-15"><a href="#cb12-15"></a>  <span class="kw">struct</span> std<span class="op">::</span>tuple_element<span class="op">&lt;</span>I, Tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb12-16"><a href="#cb12-16"></a>    <span class="kw">using</span> type <span class="op">=</span> <span class="op">[:</span> template_arguments_of<span class="op">(^</span>Tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;)[</span>I<span class="op">]</span> <span class="op">:]</span>;</span>
<span id="cb12-17"><a href="#cb12-17"></a>  <span class="op">}</span>;</span>
<span id="cb12-18"><a href="#cb12-18"></a></span>
<span id="cb12-19"><a href="#cb12-19"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> I, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb12-20"><a href="#cb12-20"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> get<span class="op">(</span>Tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;</span> <span class="op">&amp;</span>t<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> std<span class="op">::</span>tuple_element_t<span class="op">&lt;</span>I, Tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;&amp;</span> <span class="op">{</span></span>
<span id="cb12-21"><a href="#cb12-21"></a>    <span class="cf">return</span> t<span class="op">.</span>data<span class="op">.[:</span>nonstatic_data_members_of<span class="op">(^</span><span class="kw">decltype</span><span class="op">(</span>t<span class="op">.</span>data<span class="op">))[</span>I<span class="op">]:]</span>;</span>
<span id="cb12-22"><a href="#cb12-22"></a>  <span class="op">}</span></span>
<span id="cb12-23"><a href="#cb12-23"></a></span>
<span id="cb12-24"><a href="#cb12-24"></a><span class="co">// Similarly for other value categories...</span></span></code></pre></div>
</blockquote>
<p>This example uses a “magic” <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>synth_struct</code> template along with member reflection through the <code class="sourceCode cpp">members_of</code> metafunction to implement a <code class="sourceCode cpp">std<span class="op">::</span>tuple</code>-like type without the usual complex and costly template metaprogramming tricks that that involves when these facilities are not available.</p>
<h2 data-number="2.9" id="struct-to-struct-of-arrays"><span class="header-section-number">2.9</span> Struct to Struct of Arrays<a href="#struct-to-struct-of-arrays" class="self-link"></a></h2>
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> make_struct_of_arrays<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info type, <span class="dt">size_t</span> n<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>info<span class="op">&gt;</span> new_members;</span>
<span id="cb13-3"><a href="#cb13-3"></a>  <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info member <span class="op">:</span> nonstatic_data_members_of<span class="op">(</span>type<span class="op">))</span> <span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4"></a>    <span class="kw">auto</span> array_type <span class="op">=</span> substitute<span class="op">(^</span>std<span class="op">::</span>array, <span class="op">{</span>type_of<span class="op">(</span>member<span class="op">)</span>, reflect_value<span class="op">(</span>n<span class="op">)})</span>;</span>
<span id="cb13-5"><a href="#cb13-5"></a>    new_members<span class="op">.</span>push_back<span class="op">(</span>nsdm_description<span class="op">(</span>array_type, <span class="op">{.</span>name <span class="op">=</span> name_of<span class="op">(</span>member<span class="op">)}))</span>;</span>
<span id="cb13-6"><a href="#cb13-6"></a>  <span class="op">}</span></span>
<span id="cb13-7"><a href="#cb13-7"></a>  <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>synth_struct<span class="op">(</span>new_members<span class="op">)</span>;</span>
<span id="cb13-8"><a href="#cb13-8"></a><span class="op">}</span></span>
<span id="cb13-9"><a href="#cb13-9"></a></span>
<span id="cb13-10"><a href="#cb13-10"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb13-11"><a href="#cb13-11"></a><span class="kw">using</span> struct_of_arrays <span class="op">=</span> <span class="op">[:</span> make_struct_of_arrays<span class="op">(^</span>T, N<span class="op">)</span> <span class="op">:]</span>;</span></code></pre></div>
</blockquote>
<p>Example:</p>
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a><span class="kw">struct</span> point <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2"></a>  <span class="dt">float</span> x;</span>
<span id="cb14-3"><a href="#cb14-3"></a>  <span class="dt">float</span> y;</span>
<span id="cb14-4"><a href="#cb14-4"></a>  <span class="dt">float</span> z;</span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="op">}</span>;</span>
<span id="cb14-6"><a href="#cb14-6"></a></span>
<span id="cb14-7"><a href="#cb14-7"></a><span class="kw">using</span> points <span class="op">=</span> struct_of_arrays<span class="op">&lt;</span>point, <span class="dv">30</span><span class="op">&gt;</span>;</span>
<span id="cb14-8"><a href="#cb14-8"></a><span class="co">// equivalent to:</span></span>
<span id="cb14-9"><a href="#cb14-9"></a><span class="co">// struct points {</span></span>
<span id="cb14-10"><a href="#cb14-10"></a><span class="co">//   std::array&lt;float, 30&gt; x;</span></span>
<span id="cb14-11"><a href="#cb14-11"></a><span class="co">//   std::array&lt;float, 30&gt; y;</span></span>
<span id="cb14-12"><a href="#cb14-12"></a><span class="co">//   std::array&lt;float, 30&gt; z;</span></span>
<span id="cb14-13"><a href="#cb14-13"></a><span class="co">// };</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.10" id="parsing-command-line-options-ii"><span class="header-section-number">2.10</span> Parsing Command-Line Options II<a href="#parsing-command-line-options-ii" class="self-link"></a></h2>
<p>Now that we’ve seen a couple examples of using <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>synth_struct</code> to create a type, we can create a more sophisticated command-line parser example. This isn’t a complete implementation, but hopefully is enough to demonstrate the utility. This is the opening example for <a href="https://docs.rs/clap/latest/clap/">clap</a> (Rust’s <strong>C</strong>ommand <strong>L</strong>ine <strong>A</strong>rgument <strong>P</strong>arser):</p>
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1"></a><span class="kw">struct</span> Args <span class="op">:</span> Clap <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2"></a>  Option<span class="op">&lt;</span>std<span class="op">::</span>string, <span class="op">{.</span>use_short<span class="op">=</span><span class="kw">true</span>, <span class="op">.</span>use_long<span class="op">=</span><span class="kw">true</span><span class="op">}&gt;</span> name;</span>
<span id="cb15-3"><a href="#cb15-3"></a>  Option<span class="op">&lt;</span><span class="dt">int</span>, <span class="op">{.</span>use_short<span class="op">=</span><span class="kw">true</span>, <span class="op">.</span>use_long<span class="op">=</span><span class="kw">true</span><span class="op">}&gt;</span> count <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="op">}</span>;</span>
<span id="cb15-5"><a href="#cb15-5"></a></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc, <span class="dt">char</span><span class="op">**</span> argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-7"><a href="#cb15-7"></a>  <span class="kw">auto</span> opts <span class="op">=</span> Args<span class="op">{}.</span>parse<span class="op">(</span>argc, argv<span class="op">)</span>;</span>
<span id="cb15-8"><a href="#cb15-8"></a></span>
<span id="cb15-9"><a href="#cb15-9"></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> opts<span class="op">.</span>count; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span>  <span class="co">// opts.count has type int</span></span>
<span id="cb15-10"><a href="#cb15-10"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;Hello {}!&quot;</span>, opts<span class="op">.</span>name<span class="op">)</span>;   <span class="co">// opts.name has type std::string</span></span>
<span id="cb15-11"><a href="#cb15-11"></a>  <span class="op">}</span></span>
<span id="cb15-12"><a href="#cb15-12"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Which we can implement like this:</p>
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1"></a><span class="kw">struct</span> Flags <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2"></a>  <span class="dt">bool</span> use_short;</span>
<span id="cb16-3"><a href="#cb16-3"></a>  <span class="dt">bool</span> use_long;</span>
<span id="cb16-4"><a href="#cb16-4"></a><span class="op">}</span>;</span>
<span id="cb16-5"><a href="#cb16-5"></a></span>
<span id="cb16-6"><a href="#cb16-6"></a><span class="co">// type that has a member optional&lt;T&gt; with some suitable constructors and members</span></span>
<span id="cb16-7"><a href="#cb16-7"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, Flags flags<span class="op">&gt;</span></span>
<span id="cb16-8"><a href="#cb16-8"></a><span class="kw">struct</span> Option;</span>
<span id="cb16-9"><a href="#cb16-9"></a></span>
<span id="cb16-10"><a href="#cb16-10"></a><span class="co">// convert a type (all of whose non-static data members are specializations of Option)</span></span>
<span id="cb16-11"><a href="#cb16-11"></a><span class="co">// to a type that is just the appropriate members.</span></span>
<span id="cb16-12"><a href="#cb16-12"></a><span class="co">// For example, if type is a reflection of the Args presented above, then this</span></span>
<span id="cb16-13"><a href="#cb16-13"></a><span class="co">// function would evaluate to a reflection of the type</span></span>
<span id="cb16-14"><a href="#cb16-14"></a><span class="co">// struct {</span></span>
<span id="cb16-15"><a href="#cb16-15"></a><span class="co">//   std::string name;</span></span>
<span id="cb16-16"><a href="#cb16-16"></a><span class="co">//   int count;</span></span>
<span id="cb16-17"><a href="#cb16-17"></a><span class="co">// }</span></span>
<span id="cb16-18"><a href="#cb16-18"></a><span class="kw">consteval</span> <span class="kw">auto</span> spec_to_opts<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info type<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info <span class="op">{</span></span>
<span id="cb16-19"><a href="#cb16-19"></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> new_members;</span>
<span id="cb16-20"><a href="#cb16-20"></a>  <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info member <span class="op">:</span> nonstatic_data_members_of<span class="op">(</span>type<span class="op">))</span> <span class="op">{</span></span>
<span id="cb16-21"><a href="#cb16-21"></a>    <span class="kw">auto</span> new_type <span class="op">=</span> template_arguments_of<span class="op">(</span>type_of<span class="op">(</span>member<span class="op">))[</span><span class="dv">0</span><span class="op">]</span>;</span>
<span id="cb16-22"><a href="#cb16-22"></a>    new_members<span class="op">.</span>push_back<span class="op">(</span>nsdm_description<span class="op">(</span>new_type, <span class="op">{.</span>name<span class="op">=</span>name_of<span class="op">(</span>member<span class="op">)}))</span>;</span>
<span id="cb16-23"><a href="#cb16-23"></a>  <span class="op">}</span></span>
<span id="cb16-24"><a href="#cb16-24"></a>  <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>synth_struct<span class="op">(</span>new_members<span class="op">)</span>;</span>
<span id="cb16-25"><a href="#cb16-25"></a><span class="op">}</span></span>
<span id="cb16-26"><a href="#cb16-26"></a></span>
<span id="cb16-27"><a href="#cb16-27"></a><span class="kw">struct</span> Clap <span class="op">{</span></span>
<span id="cb16-28"><a href="#cb16-28"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Spec<span class="op">&gt;</span></span>
<span id="cb16-29"><a href="#cb16-29"></a>  <span class="kw">auto</span> parse<span class="op">(</span><span class="kw">this</span> Spec <span class="kw">const</span><span class="op">&amp;</span> spec, <span class="dt">int</span> argc, <span class="dt">char</span><span class="op">**</span> argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-30"><a href="#cb16-30"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string_view<span class="op">&gt;</span> cmdline<span class="op">(</span>argv<span class="op">+</span><span class="dv">1</span>, argv<span class="op">+</span>argc<span class="op">)</span></span>
<span id="cb16-31"><a href="#cb16-31"></a></span>
<span id="cb16-32"><a href="#cb16-32"></a>    <span class="co">// check if cmdline contains --help, etc.</span></span>
<span id="cb16-33"><a href="#cb16-33"></a></span>
<span id="cb16-34"><a href="#cb16-34"></a>    <span class="kw">using</span> Opts <span class="op">=</span> <span class="op">[:</span> spec_to_opts<span class="op">(^</span>Spec<span class="op">)</span> <span class="op">:]</span>;</span>
<span id="cb16-35"><a href="#cb16-35"></a>    Opts opts;</span>
<span id="cb16-36"><a href="#cb16-36"></a></span>
<span id="cb16-37"><a href="#cb16-37"></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> <span class="op">[</span>sm, om<span class="op">]</span> <span class="op">:</span> std<span class="op">::</span>views<span class="op">::</span>zip<span class="op">(</span>nonstatic_data_members_of<span class="op">(^</span>Spec<span class="op">)</span>,</span>
<span id="cb16-38"><a href="#cb16-38"></a>                                                            nonstatic_data_members_of<span class="op">(^</span>Opts<span class="op">)))</span> <span class="op">{</span></span>
<span id="cb16-39"><a href="#cb16-39"></a>      <span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> cur <span class="op">=</span> spec<span class="op">.[:</span>sm<span class="op">:]</span>;</span>
<span id="cb16-40"><a href="#cb16-40"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> type <span class="op">=</span> type_of<span class="op">(</span>om<span class="op">)</span>;</span>
<span id="cb16-41"><a href="#cb16-41"></a></span>
<span id="cb16-42"><a href="#cb16-42"></a>      <span class="co">// find the argument associated with this option</span></span>
<span id="cb16-43"><a href="#cb16-43"></a>      <span class="kw">auto</span> it <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>find_if<span class="op">(</span>cmdline,</span>
<span id="cb16-44"><a href="#cb16-44"></a>        <span class="op">[&amp;](</span>std<span class="op">::</span>string_view arg<span class="op">){</span></span>
<span id="cb16-45"><a href="#cb16-45"></a>          <span class="cf">return</span> <span class="op">(</span>cur<span class="op">.</span>use_short <span class="op">&amp;&amp;</span> arg<span class="op">.</span>starts_with<span class="op">(</span><span class="st">&quot;-&quot;</span><span class="op">)</span> <span class="op">&amp;&amp;</span> arg<span class="op">.</span>substr<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> name_of<span class="op">(</span>sm<span class="op">))</span></span>
<span id="cb16-46"><a href="#cb16-46"></a>              <span class="op">||</span> <span class="op">(</span>cur<span class="op">.</span>use_long <span class="op">&amp;&amp;</span> arg<span class="op">.</span>starts_with<span class="op">(</span><span class="st">&quot;--&quot;</span><span class="op">)</span> <span class="op">&amp;&amp;</span> arg<span class="op">.</span>substr<span class="op">(</span><span class="dv">2</span><span class="op">)</span> <span class="op">==</span> name_of<span class="op">(</span>sm<span class="op">))</span>;</span>
<span id="cb16-47"><a href="#cb16-47"></a>        <span class="op">})</span>;</span>
<span id="cb16-48"><a href="#cb16-48"></a></span>
<span id="cb16-49"><a href="#cb16-49"></a>      <span class="co">// no such argument</span></span>
<span id="cb16-50"><a href="#cb16-50"></a>      <span class="cf">if</span> <span class="op">(</span>it <span class="op">==</span> cmdline<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb16-51"><a href="#cb16-51"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>template_of<span class="op">(</span>om<span class="op">)</span> <span class="op">==</span> <span class="op">^</span>std<span class="op">::</span>optional<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-52"><a href="#cb16-52"></a>          <span class="co">// the type is optional, so the argument is too</span></span>
<span id="cb16-53"><a href="#cb16-53"></a>          <span class="cf">continue</span>;</span>
<span id="cb16-54"><a href="#cb16-54"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>cur<span class="op">.</span>initializer<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-55"><a href="#cb16-55"></a>          <span class="co">// the type isn&#39;t optional, but an initializer is provided, use that</span></span>
<span id="cb16-56"><a href="#cb16-56"></a>          opts<span class="op">.[:</span>om<span class="op">:]</span> <span class="op">=</span> <span class="op">*</span>cur<span class="op">.</span>initializer;</span>
<span id="cb16-57"><a href="#cb16-57"></a>          <span class="cf">continue</span>;</span>
<span id="cb16-58"><a href="#cb16-58"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb16-59"><a href="#cb16-59"></a>          std<span class="op">::</span>print<span class="op">(</span>stderr, <span class="st">&quot;Missing required option {}</span><span class="sc">\n</span><span class="st">&quot;</span>, name_of<span class="op">(</span>sm<span class="op">))</span>;</span>
<span id="cb16-60"><a href="#cb16-60"></a>          std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb16-61"><a href="#cb16-61"></a>        <span class="op">}</span></span>
<span id="cb16-62"><a href="#cb16-62"></a>      <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>it <span class="op">+</span> <span class="dv">1</span> <span class="op">==</span> cmdline<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb16-63"><a href="#cb16-63"></a>        std<span class="op">::</span>print<span class="op">(</span>stderr, <span class="st">&quot;Option {} for {} is missing a value</span><span class="sc">\n</span><span class="st">&quot;</span>, <span class="op">*</span>it, name_of<span class="op">(</span>sm<span class="op">))</span>;</span>
<span id="cb16-64"><a href="#cb16-64"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb16-65"><a href="#cb16-65"></a>      <span class="op">}</span></span>
<span id="cb16-66"><a href="#cb16-66"></a></span>
<span id="cb16-67"><a href="#cb16-67"></a>      <span class="co">// found our argument, try to parse it</span></span>
<span id="cb16-68"><a href="#cb16-68"></a>      <span class="kw">auto</span> iss <span class="op">=</span> ispanstream<span class="op">(</span>it<span class="op">[</span><span class="dv">1</span><span class="op">])</span>;</span>
<span id="cb16-69"><a href="#cb16-69"></a>      <span class="cf">if</span> <span class="op">(</span>iss <span class="op">&gt;&gt;</span> opts<span class="op">.[:</span>om<span class="op">:]</span>; <span class="op">!</span>iss<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-70"><a href="#cb16-70"></a>        std<span class="op">::</span>print<span class="op">(</span>stderr, <span class="st">&quot;Failed to parse {:?} into option {} of type {}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb16-71"><a href="#cb16-71"></a>          <span class="op">*</span>it, name_of<span class="op">(</span>sm<span class="op">)</span>, display_name_of<span class="op">(</span>type<span class="op">))</span>;</span>
<span id="cb16-72"><a href="#cb16-72"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb16-73"><a href="#cb16-73"></a>      <span class="op">}</span></span>
<span id="cb16-74"><a href="#cb16-74"></a>    <span class="op">}</span></span>
<span id="cb16-75"><a href="#cb16-75"></a>    <span class="cf">return</span> opts;</span>
<span id="cb16-76"><a href="#cb16-76"></a>  <span class="op">}</span></span>
<span id="cb16-77"><a href="#cb16-77"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.11" id="a-universal-formatter"><span class="header-section-number">2.11</span> A Universal Formatter<a href="#a-universal-formatter" class="self-link"></a></h2>
<p>This example is taken from Boost.Describe:</p>
<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a><span class="kw">struct</span> universal_formatter <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> ctx<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb17-3"><a href="#cb17-3"></a></span>
<span id="cb17-4"><a href="#cb17-4"></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="cb17-5"><a href="#cb17-5"></a>  <span class="kw">auto</span> format<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> t, <span class="kw">auto</span><span class="op">&amp;</span> ctx<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb17-6"><a href="#cb17-6"></a>    <span class="kw">auto</span> out <span class="op">=</span> std<span class="op">::</span>format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;{}{{&quot;</span>, name_of<span class="op">(^</span>T<span class="op">))</span>;</span>
<span id="cb17-7"><a href="#cb17-7"></a></span>
<span id="cb17-8"><a href="#cb17-8"></a>    <span class="kw">auto</span> delim <span class="op">=</span> <span class="op">[</span>first<span class="op">=</span><span class="kw">true</span><span class="op">]()</span> <span class="kw">mutable</span> <span class="op">{</span></span>
<span id="cb17-9"><a href="#cb17-9"></a>      <span class="cf">if</span> <span class="op">(!</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-10"><a href="#cb17-10"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb17-11"><a href="#cb17-11"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb17-12"><a href="#cb17-12"></a>      <span class="op">}</span></span>
<span id="cb17-13"><a href="#cb17-13"></a>      first <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb17-14"><a href="#cb17-14"></a>    <span class="op">}</span>;</span>
<span id="cb17-15"><a href="#cb17-15"></a></span>
<span id="cb17-16"><a href="#cb17-16"></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> base <span class="op">:</span> bases_of<span class="op">(^</span>T<span class="op">))</span> <span class="op">{</span></span>
<span id="cb17-17"><a href="#cb17-17"></a>      delim<span class="op">()</span>;</span>
<span id="cb17-18"><a href="#cb17-18"></a>      out <span class="op">=</span> std<span class="op">::</span>format_to<span class="op">(</span>out, <span class="st">&quot;{}&quot;</span>, <span class="kw">static_cast</span><span class="op">&lt;[:</span>base<span class="op">:]</span> <span class="kw">const</span><span class="op">&amp;&gt;(</span>t<span class="op">))</span>;</span>
<span id="cb17-19"><a href="#cb17-19"></a>    <span class="op">}</span></span>
<span id="cb17-20"><a href="#cb17-20"></a></span>
<span id="cb17-21"><a href="#cb17-21"></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>T<span class="op">))</span> <span class="op">{</span></span>
<span id="cb17-22"><a href="#cb17-22"></a>      delim<span class="op">()</span>;</span>
<span id="cb17-23"><a href="#cb17-23"></a>      out <span class="op">=</span> std<span class="op">::</span>format_to<span class="op">(</span>out, <span class="st">&quot;.{}={}&quot;</span>, name_of<span class="op">(</span>mem<span class="op">)</span>, t<span class="op">.[:</span>mem<span class="op">:])</span>;</span>
<span id="cb17-24"><a href="#cb17-24"></a>    <span class="op">}</span></span>
<span id="cb17-25"><a href="#cb17-25"></a></span>
<span id="cb17-26"><a href="#cb17-26"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;}&#39;</span>;</span>
<span id="cb17-27"><a href="#cb17-27"></a>    <span class="cf">return</span> out;</span>
<span id="cb17-28"><a href="#cb17-28"></a>  <span class="op">}</span></span>
<span id="cb17-29"><a href="#cb17-29"></a><span class="op">}</span>;</span>
<span id="cb17-30"><a href="#cb17-30"></a></span>
<span id="cb17-31"><a href="#cb17-31"></a><span class="kw">struct</span> X <span class="op">{</span> <span class="dt">int</span> m1 <span class="op">=</span> <span class="dv">1</span>; <span class="op">}</span>;</span>
<span id="cb17-32"><a href="#cb17-32"></a><span class="kw">struct</span> Y <span class="op">{</span> <span class="dt">int</span> m2 <span class="op">=</span> <span class="dv">2</span>; <span class="op">}</span>;</span>
<span id="cb17-33"><a href="#cb17-33"></a><span class="kw">class</span> Z <span class="op">:</span> <span class="kw">public</span> X, <span class="kw">private</span> Y <span class="op">{</span> <span class="dt">int</span> m3 <span class="op">=</span> <span class="dv">3</span>; <span class="dt">int</span> m4 <span class="op">=</span> <span class="dv">4</span>; <span class="op">}</span>;</span>
<span id="cb17-34"><a href="#cb17-34"></a></span>
<span id="cb17-35"><a href="#cb17-35"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span> <span class="kw">struct</span> std<span class="op">::</span>formatter<span class="op">&lt;</span>X<span class="op">&gt;</span> <span class="op">:</span> universal_formatter <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb17-36"><a href="#cb17-36"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span> <span class="kw">struct</span> std<span class="op">::</span>formatter<span class="op">&lt;</span>Y<span class="op">&gt;</span> <span class="op">:</span> universal_formatter <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb17-37"><a href="#cb17-37"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span> <span class="kw">struct</span> std<span class="op">::</span>formatter<span class="op">&lt;</span>Z<span class="op">&gt;</span> <span class="op">:</span> universal_formatter <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb17-38"><a href="#cb17-38"></a></span>
<span id="cb17-39"><a href="#cb17-39"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb17-40"><a href="#cb17-40"></a>    std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;{}&quot;</span>, Z<span class="op">())</span>; <span class="co">// Z{X{.m1 = 1}, Y{.m2 = 2}, .m3 = 3, .m4 = 4}</span></span>
<span id="cb17-41"><a href="#cb17-41"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.12" id="implementing-member-wise-hash_append"><span class="header-section-number">2.12</span> Implementing member-wise <code class="sourceCode cpp">hash_append</code><a href="#implementing-member-wise-hash_append" class="self-link"></a></h2>
<p>Based on the <span class="citation" data-cites="N3980">[<a href="#ref-N3980" role="doc-biblioref">N3980</a>]</span> API:</p>
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> H, <span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">requires</span> std<span class="op">::</span>is_standard_layout_v<span class="op">&lt;</span>T<span class="op">&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2"></a><span class="dt">void</span> hash_append<span class="op">(</span>H<span class="op">&amp;</span> algo, T <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-3"><a href="#cb18-3"></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>T<span class="op">))</span> <span class="op">{</span></span>
<span id="cb18-4"><a href="#cb18-4"></a>        hash_append<span class="op">(</span>algo, t<span class="op">.[:</span>mem<span class="op">:])</span>;</span>
<span id="cb18-5"><a href="#cb18-5"></a>    <span class="op">}</span></span>
<span id="cb18-6"><a href="#cb18-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="2.13" id="converting-a-struct-to-a-tuple"><span class="header-section-number">2.13</span> Converting a Struct to a Tuple<a href="#converting-a-struct-to-a-tuple" class="self-link"></a></h2>
<p>This approach requires allowing packs in structured bindings <span class="citation" data-cites="P1061R5">[<a href="#ref-P1061R5" role="doc-biblioref">P1061R5</a>]</span>, but can also be written using <code class="sourceCode cpp">std<span class="op">::</span>make_index_sequence</code>:</p>
<blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-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="cb19-2"><a href="#cb19-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>T<span class="op">)</span>;</span>
<span id="cb19-4"><a href="#cb19-4"></a></span>
<span id="cb19-5"><a href="#cb19-5"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> indices <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb19-6"><a href="#cb19-6"></a>    std<span class="op">::</span>array<span class="op">&lt;</span><span class="dt">int</span>, members<span class="op">.</span>size<span class="op">()&gt;</span> indices;</span>
<span id="cb19-7"><a href="#cb19-7"></a>    std<span class="op">::</span>ranges<span class="op">::</span>iota<span class="op">(</span>indices, <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb19-8"><a href="#cb19-8"></a>    <span class="cf">return</span> indices;</span>
<span id="cb19-9"><a href="#cb19-9"></a>  <span class="op">}()</span>;</span>
<span id="cb19-10"><a href="#cb19-10"></a></span>
<span id="cb19-11"><a href="#cb19-11"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="op">[...</span>Is<span class="op">]</span> <span class="op">=</span> indices;</span>
<span id="cb19-12"><a href="#cb19-12"></a>  <span class="cf">return</span> std<span class="op">::</span>make_tuple<span class="op">(</span>t<span class="op">.[:</span> members<span class="op">[</span>Is<span class="op">]</span> <span class="op">:]...)</span>;</span>
<span id="cb19-13"><a href="#cb19-13"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>An alternative approach is:</p>
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> struct_to_tuple_type<span class="op">(</span>info type<span class="op">)</span> <span class="op">-&gt;</span> info <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>std<span class="op">::</span>tuple,</span>
<span id="cb20-3"><a href="#cb20-3"></a>                    nonstatic_data_members_of<span class="op">(</span>type<span class="op">)</span></span>
<span id="cb20-4"><a href="#cb20-4"></a>                    <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>transform<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>type_of<span class="op">)</span></span>
<span id="cb20-5"><a href="#cb20-5"></a>                    <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>transform<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>remove_cvref<span class="op">)</span></span>
<span id="cb20-6"><a href="#cb20-6"></a>                    <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>to<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&gt;())</span>;</span>
<span id="cb20-7"><a href="#cb20-7"></a><span class="op">}</span></span>
<span id="cb20-8"><a href="#cb20-8"></a></span>
<span id="cb20-9"><a href="#cb20-9"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> To, <span class="kw">typename</span> From, std<span class="op">::</span>meta<span class="op">::</span>info <span class="op">...</span> members<span class="op">&gt;</span></span>
<span id="cb20-10"><a href="#cb20-10"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple_helper<span class="op">(</span>From <span class="kw">const</span><span class="op">&amp;</span> from<span class="op">)</span> <span class="op">-&gt;</span> To <span class="op">{</span></span>
<span id="cb20-11"><a href="#cb20-11"></a>  <span class="cf">return</span> To<span class="op">(</span>from<span class="op">.[:</span>members<span class="op">:]...)</span>;</span>
<span id="cb20-12"><a href="#cb20-12"></a><span class="op">}</span></span>
<span id="cb20-13"><a href="#cb20-13"></a></span>
<span id="cb20-14"><a href="#cb20-14"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> From<span class="op">&gt;</span></span>
<span id="cb20-15"><a href="#cb20-15"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple<span class="op">(</span>From <span class="kw">const</span><span class="op">&amp;</span> from<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-16"><a href="#cb20-16"></a>  <span class="kw">using</span> To <span class="op">=</span> <span class="op">[:</span> struct_to_tuple_type<span class="op">(^</span>From<span class="op">):</span> <span class="op">]</span>;</span>
<span id="cb20-17"><a href="#cb20-17"></a></span>
<span id="cb20-18"><a href="#cb20-18"></a>  std<span class="op">::</span>vector args <span class="op">=</span> <span class="op">{^</span>To, <span class="op">^</span>From<span class="op">}</span>;</span>
<span id="cb20-19"><a href="#cb20-19"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> mem <span class="op">:</span> nonstatic_data_members_of<span class="op">(^</span>From<span class="op">))</span> <span class="op">{</span></span>
<span id="cb20-20"><a href="#cb20-20"></a>    args<span class="op">.</span>push_back<span class="op">(</span>reflect_value<span class="op">(</span>mem<span class="op">))</span>;</span>
<span id="cb20-21"><a href="#cb20-21"></a>  <span class="op">}</span></span>
<span id="cb20-22"><a href="#cb20-22"></a></span>
<span id="cb20-23"><a href="#cb20-23"></a>  <span class="kw">auto</span> f <span class="op">=</span> entity_ref<span class="op">&lt;</span>To<span class="op">(</span>From <span class="kw">const</span><span class="op">&amp;)&gt;(</span>substitute<span class="op">(^</span>struct_to_tuple_helper, args<span class="op">))</span>;</span>
<span id="cb20-24"><a href="#cb20-24"></a>  <span class="cf">return</span> f<span class="op">(</span>from<span class="op">)</span>;</span>
<span id="cb20-25"><a href="#cb20-25"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Here, <code class="sourceCode cpp">struct_to_tuple_type</code> takes a reflection of a type like <code class="sourceCode cpp"><span class="kw">struct</span> <span class="op">{</span> T t; U <span class="kw">const</span><span class="op">&amp;</span> u; V v; <span class="op">}</span></code> and returns a reflection of the type <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>T, U, V<span class="op">&gt;</span></code>. <code class="sourceCode cpp">helper</code>. That gives us the return type. Then, <code class="sourceCode cpp">struct_to_tuple_helper</code> is a function template that does the actual conversion - which it can do by having all the reflections of the members as a non-type template parameter pack.</p>
<p>Everything is put together by using <code class="sourceCode cpp">substitute</code> to create the instantiation of <code class="sourceCode cpp">struct_to_tuple_helper</code> that we need, which is use <code class="sourceCode cpp">entity_ref</code> to get the correct function out of. <code class="sourceCode cpp">f</code> there is a function pointer to the correct specialization of <code class="sourceCode cpp">struct_to_tuple_helper</code>. Which we can simply invoke.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposed-features"><span class="header-section-number">3</span> Proposed Features<a href="#proposed-features" class="self-link"></a></h1>
<h2 data-number="3.1" id="the-reflection-operator"><span class="header-section-number">3.1</span> The Reflection Operator (<code class="sourceCode cpp"><span class="op">^</span></code>)<a href="#the-reflection-operator" class="self-link"></a></h2>
<p>The reflection operator produces a reflection value from a grammatical construct (its operand):</p>
<blockquote>
<div class="line-block"><em>unary-expression</em>:<br />
      …<br />
      <code class="sourceCode cpp"><span class="op">^</span></code> <code class="sourceCode cpp"><span class="op">::</span></code><br />
      <code class="sourceCode cpp"><span class="op">^</span></code> <em>namespace-name</em><br />
      <code class="sourceCode cpp"><span class="op">^</span></code> <em>type-id</em><br />
      <code class="sourceCode cpp"><span class="op">^</span></code> <em>cast-expression</em></div>
</blockquote>
<p>Note that <em>cast-expression</em> includes <em>id-expression</em>, which in turn can designate templates, member names, etc.</p>
<p>The current proposal requires that the <em>cast-expression</em> be:</p>
<ul>
<li>a <em>primary-expression</em> referring to a function or member function, or</li>
<li>a <em>primary-expression</em> referring to a variable, static data member, or structured binding, or</li>
<li>a <em>primary-expression</em> referring to a nonstatic data member, or</li>
<li>a <em>primary-expression</em> referring to a template, or</li>
<li>a constant-expression.</li>
</ul>
<p>In a SFINAE context, a failure to substitute the operand of a reflection operator construct causes that construct to evaluate to an invalid reflection.</p>
<h2 data-number="3.2" id="splicers"><span class="header-section-number">3.2</span> Splicers (<code class="sourceCode cpp"><span class="op">[:</span></code>…<code class="sourceCode cpp"><span class="op">:]</span></code>)<a href="#splicers" class="self-link"></a></h2>
<p>A reflection that is not an invalid reflection can be “spliced” into source code using one of several <em>splicer</em> forms:</p>
<ul>
<li><code class="sourceCode cpp"><span class="op">[:</span> r <span class="op">:]</span></code> produces an <em>expression</em> evaluating to the entity or constant value represented by <code class="sourceCode cpp">r</code>.</li>
<li><code class="sourceCode cpp"><span class="kw">typename</span><span class="op">[:</span> r <span class="op">:]</span></code> produces a <em>simple-type-specifier</em> corresponding to the type represented by <code class="sourceCode cpp">r</code>.</li>
<li><code class="sourceCode cpp"><span class="kw">template</span><span class="op">[:</span> r <span class="op">:]</span></code> produces a <em>template-name</em> corresponding to the template represented by <code class="sourceCode cpp">r</code>.</li>
<li><code class="sourceCode cpp"><span class="kw">namespace</span><span class="op">[:</span> r <span class="op">:]</span></code> produces a <em>namespace-name</em> corresponding to the namespace represented by <code class="sourceCode cpp">r</code>.</li>
<li><code class="sourceCode cpp"><span class="op">[:</span>r<span class="op">:]::</span></code> produces a <em>nested-name-specifier</em> corresponding to the namespace, enumeration type, or class type represented by <code class="sourceCode cpp">r</code>.</li>
</ul>
<p>Attempting to splice a reflection value that does not meet the requirement of the splice (including “invalid reflections”) is ill-formed. For example:</p>
<blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a><span class="kw">typename</span><span class="op">[:</span> <span class="op">^::</span> <span class="op">:]</span> x <span class="op">=</span> <span class="dv">0</span>;  <span class="co">// Error.</span></span></code></pre></div>
</blockquote>
<p>A quality implementation should emit the diagnostic text associated with an invalid reflection when attempting to splice that invalid reflection.</p>
<p>(This proposal does not at this time propose range-based splicers as described in P1240. We still believe that those are desirable. However, they are more complex to implement and they involve syntactic choices that benefit from being considered along with other proposals that introduce pack-like constructs in non-template contexts. Meanwhile, we found that many very useful techniques are enabled with just the basic splicers presented here.)</p>
<h3 data-number="3.2.1" id="range-splicers"><span class="header-section-number">3.2.1</span> Range Splicers<a href="#range-splicers" class="self-link"></a></h3>
<p>The splicers described above all take a single object of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> (described in more detail below). However, there are many cases where we don’t have a single reflection, we have a range of reflections - and we want to splice them all in one go. For that, we need a different form of splicer: a range splicer.</p>
<p>Construct the <a href="#converting-a-struct-to-a-tuple">struct-to-tuple</a> example from above. It was demonstrates using a single splice, but it would be simpler if we had a range splice:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>With Single Splice</strong>
</div></th>
<th><div style="text-align:center">
<strong>With Range Splice</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-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="cb22-2"><a href="#cb22-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-3"><a href="#cb22-3"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>T<span class="op">)</span>;</span>
<span id="cb22-4"><a href="#cb22-4"></a></span>
<span id="cb22-5"><a href="#cb22-5"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> indices <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb22-6"><a href="#cb22-6"></a>    std<span class="op">::</span>array<span class="op">&lt;</span><span class="dt">int</span>, members<span class="op">.</span>size<span class="op">()&gt;</span> indices;</span>
<span id="cb22-7"><a href="#cb22-7"></a>    std<span class="op">::</span>ranges<span class="op">::</span>iota<span class="op">(</span>indices, <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb22-8"><a href="#cb22-8"></a>    <span class="cf">return</span> indices;</span>
<span id="cb22-9"><a href="#cb22-9"></a>  <span class="op">}()</span>;</span>
<span id="cb22-10"><a href="#cb22-10"></a></span>
<span id="cb22-11"><a href="#cb22-11"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="op">[...</span>Is<span class="op">]</span> <span class="op">=</span> indices;</span>
<span id="cb22-12"><a href="#cb22-12"></a>  <span class="cf">return</span> std<span class="op">::</span>make_tuple<span class="op">(</span>t<span class="op">.[:</span> members<span class="op">[</span>Is<span class="op">]</span> <span class="op">:]...)</span>;</span>
<span id="cb22-13"><a href="#cb22-13"></a><span class="op">}</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-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="cb23-2"><a href="#cb23-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>T<span class="op">)</span>;</span>
<span id="cb23-4"><a href="#cb23-4"></a>  <span class="cf">return</span> std<span class="op">::</span>make_tuple<span class="op">(</span>t<span class="op">.[:</span> <span class="op">...</span>members <span class="op">:]...)</span>;</span>
<span id="cb23-5"><a href="#cb23-5"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>A range splice, <code class="sourceCode cpp"><span class="op">[:</span> <span class="op">...</span> r <span class="op">:]</span></code>, would accept as its argument a constant range of <code class="sourceCode cpp">meta<span class="op">::</span>info</code>, <code class="sourceCode cpp">r</code>, and would behave as an unexpanded pack of splices. So the above expression</p>
<blockquote>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></a>make_tuple<span class="op">(</span>t<span class="op">.[:</span> <span class="op">...</span> members <span class="op">:]...)</span></span></code></pre></div>
</blockquote>
<p>would evaluate as</p>
<blockquote>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a>make_tuple<span class="op">(</span>t<span class="op">.[:</span>members<span class="op">[</span><span class="dv">0</span><span class="op">]:]</span>, t<span class="op">.[:</span>members<span class="op">[</span><span class="dv">1</span><span class="op">]:]</span>, <span class="op">...</span>, t<span class="op">.[:</span>members<span class="op">[</span><em>N-1</em><span class="op">]:])</span></span></code></pre></div>
</blockquote>
<p>This is a very useful facility indeed!</p>
<p>However, range splicing of dependent arguments is at least an order of magnitude harder to implement than ordinary splicing. We think that not including range splicing gives us a better chance of having reflection in C++26. Especially since, as this paper’s examples demonstrate, a lot can be done without them.</p>
<p>Another way to work around a lack of range splicing would be to implement <code class="sourceCode cpp">with_size<span class="op">&lt;</span>N<span class="op">&gt;(</span>f<span class="op">)</span></code>, which would behave like <code class="sourceCode cpp">f<span class="op">(</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">0</span><span class="op">&gt;{}</span>, integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">0</span><span class="op">&gt;{}</span>, <span class="op">...</span>, integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, N<span class="op">-</span><span class="dv">1</span><span class="op">&gt;{})</span></code>. Which is enough for a tolerable implementation:</p>
<blockquote>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> struct_to_tuple<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb26-3"><a href="#cb26-3"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> members <span class="op">=</span> nonstatic_data_members_of<span class="op">(^</span>T<span class="op">)</span>;</span>
<span id="cb26-4"><a href="#cb26-4"></a>  <span class="cf">return</span> with_size<span class="op">&lt;</span>members<span class="op">.</span>size<span class="op">()&gt;([&amp;](</span><span class="kw">auto</span><span class="op">...</span> Is<span class="op">){</span></span>
<span id="cb26-5"><a href="#cb26-5"></a>    <span class="cf">return</span> std<span class="op">::</span>make_tuple<span class="op">(</span>t<span class="op">.[:</span> members<span class="op">[</span>Is<span class="op">]</span> <span class="op">:]...)</span>;</span>
<span id="cb26-6"><a href="#cb26-6"></a>  <span class="op">})</span>;</span>
<span id="cb26-7"><a href="#cb26-7"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="3.3" id="stdmetainfo"><span class="header-section-number">3.3</span> <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code><a href="#stdmetainfo" class="self-link"></a></h2>
<p>The type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> can be defined as follows:</p>
<blockquote>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-2"></a>  <span class="kw">namespace</span> meta <span class="op">{</span></span>
<span id="cb27-3"><a href="#cb27-3"></a>    <span class="kw">using</span> info <span class="op">=</span> <span class="kw">decltype</span><span class="op">(^</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb27-4"><a href="#cb27-4"></a>  <span class="op">}</span></span>
<span id="cb27-5"><a href="#cb27-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>In our initial proposal a value of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> can represent:</p>
<ul>
<li>an error (corresponding to an “invalid reflection”)</li>
<li>any (C++) type and type-alias</li>
<li>any function or member function</li>
<li>any variable, static data member, or structured binding</li>
<li>any non-static data member</li>
<li>any constant value</li>
<li>any template</li>
<li>any namespace</li>
</ul>
<p>Notably absent at this time are general non-constant expressions (that aren’t <em>expression-id</em>s referring to variables or structured bindings). For example:</p>
<blockquote>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1"></a><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb28-2"><a href="#cb28-2"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb28-3"><a href="#cb28-3"></a>  <span class="op">[:^</span>x<span class="op">:]</span> <span class="op">=</span> <span class="dv">42</span>;     <span class="co">// Okay.  Same as: x = 42;</span></span>
<span id="cb28-4"><a href="#cb28-4"></a>  x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>x<span class="op">):]</span>;  <span class="co">// Error: &quot;2*x&quot; is a general non-constant expression.</span></span>
<span id="cb28-5"><a href="#cb28-5"></a>  <span class="kw">constexpr</span> <span class="dt">int</span> N <span class="op">=</span> <span class="dv">42</span>;</span>
<span id="cb28-6"><a href="#cb28-6"></a>  x <span class="op">=</span> <span class="op">[:^(</span><span class="dv">2</span><span class="op">*</span>N<span class="op">):]</span>;  <span class="co">// Okay: &quot;2*N&quot; is a constant-expression.</span></span>
<span id="cb28-7"><a href="#cb28-7"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Note that for <code class="sourceCode cpp"><span class="op">^(</span><span class="dv">2</span><span class="op">*</span>N<span class="op">)</span></code> an implementation only has to capture the constant value of <code class="sourceCode cpp"><span class="dv">2</span><span class="op">*</span>N</code> and not various other properties of the underlying expression (such as any temporaries it involves, etc.).</p>
<p>The type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> is a <em>scalar</em> type. Nontype template arguments of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> are permitted. The entity being reflected can affect the linkage of a template instance involving a reflection. For example:</p>
<blockquote>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> R<span class="op">&gt;</span> <span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb29-2"><a href="#cb29-2"></a></span>
<span id="cb29-3"><a href="#cb29-3"></a><span class="kw">extern</span> <span class="dt">int</span> x;</span>
<span id="cb29-4"><a href="#cb29-4"></a><span class="kw">static</span> <span class="dt">int</span> y;</span>
<span id="cb29-5"><a href="#cb29-5"></a></span>
<span id="cb29-6"><a href="#cb29-6"></a>S<span class="op">&lt;^</span>x<span class="op">&gt;</span> sx;  <span class="co">// S&lt;^x&gt; has external name linkage.</span></span>
<span id="cb29-7"><a href="#cb29-7"></a>S<span class="op">&lt;^</span>y<span class="op">&gt;</span> sy;  <span class="co">// S&lt;^y&gt; has internal name linkage.</span></span></code></pre></div>
</blockquote>
<p>Namespace <code class="sourceCode cpp">std<span class="op">::</span>meta</code> is associated with type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>: That allows the core meta functions to be invoked without explicit qualification. For example:</p>
<blockquote>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb30-2"><a href="#cb30-2"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb30-3"><a href="#cb30-3"></a>std<span class="op">::</span>string name2 <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(^</span>S<span class="op">)</span>;  <span class="co">// Okay.</span></span>
<span id="cb30-4"><a href="#cb30-4"></a>std<span class="op">::</span>string name1 <span class="op">=</span> name_of<span class="op">(^</span>S<span class="op">)</span>;             <span class="co">// Also okay.</span></span></code></pre></div>
</blockquote>
<h2 data-number="3.4" id="metafunctions"><span class="header-section-number">3.4</span> Metafunctions<a href="#metafunctions" class="self-link"></a></h2>
<p>We propose a number of metafunctions declared in namespace <code class="sourceCode cpp">std<span class="op">::</span>meta</code> to operator on reflection values. Adding metafunctions to an implementation is expected to be relatively “easy” compared to implementing the core language features described previously. However, despite offering a normal consteval C++ function interface, each on of these relies on “compiler magic” to a significant extent.</p>
<h3 data-number="3.4.1" id="invalid_reflection-is_invalid-diagnose_error"><span class="header-section-number">3.4.1</span> <code class="sourceCode cpp">invalid_reflection</code>, <code class="sourceCode cpp">is_invalid</code>, <code class="sourceCode cpp">diagnose_error</code><a href="#invalid_reflection-is_invalid-diagnose_error" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb31-2"><a href="#cb31-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> invalid_reflection<span class="op">(</span>string_view msg, source_location loc <span class="op">=</span> source_location<span class="op">::</span>current<span class="op">())</span> <span class="op">-&gt;</span> info;</span>
<span id="cb31-3"><a href="#cb31-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_invalid<span class="op">(</span>info<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb31-4"><a href="#cb31-4"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> diagnose_error<span class="op">(</span>info<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span>;</span>
<span id="cb31-5"><a href="#cb31-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>An invalid reflection represents a potential diagnostic for an erroneous construct. Some standard metafunctions will generate such invalid reflections, but user programs can also create them with the <code class="sourceCode cpp">invalid_reflection</code> metafunction. <code class="sourceCode cpp">is_invalid</code> returns true if it is given an invalid reflection. Evaluating <code class="sourceCode cpp">diagnose_error</code> renders a program ill-formed. If the given reflection is for an invalid reflection, an implementation is encouraged to render the encapsulated message and source position as part of the diagnostic indicating that the program is ill-formed.</p>
<h3 data-number="3.4.2" id="name_of-display_name_of-source_location_of"><span class="header-section-number">3.4.2</span> <code class="sourceCode cpp">name_of</code>, <code class="sourceCode cpp">display_name_of</code>, <code class="sourceCode cpp">source_location_of</code><a href="#name_of-display_name_of-source_location_of" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb32-2"><a href="#cb32-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> name_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view;</span>
<span id="cb32-3"><a href="#cb32-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> display_name_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view;</span>
<span id="cb32-4"><a href="#cb32-4"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Given a reflection <code class="sourceCode cpp">r</code> that designates a declared entity <code class="sourceCode cpp">X</code>, <code class="sourceCode cpp">name_of<span class="op">(</span>r<span class="op">)</span></code> returns a <code class="sourceCode cpp">string_view</code> holding the unqualified name of <code class="sourceCode cpp">X</code>. For all other reflections, an empty <code class="sourceCode cpp">string_view</code> is produced. For template instances, the name does not include the template argument list. The contents of the <code class="sourceCode cpp">string_view</code> consist of characters of the basic source character set only (an implementation can map other characters using universal character names).</p>
<p>Given a reflection <code class="sourceCode cpp">r</code>, <code class="sourceCode cpp">display_name_of<span class="op">(</span>r<span class="op">)</span></code> returns a unspecified non-empty <code class="sourceCode cpp">string_view</code>. Implementations are encouraged to produce text that is helpful in identifying the reflected construct.</p>
<p>Given a reflection <code class="sourceCode cpp">r</code>, <code class="sourceCode cpp">source_location_of<span class="op">(</span>r<span class="op">)</span></code> returns an unspecified <code class="sourceCode cpp">source_location</code>. Implementations are encouraged to produce the correct source location of the item designated by the reflection.</p>
<h3 data-number="3.4.3" id="type_of-parent_of-entity_of"><span class="header-section-number">3.4.3</span> <code class="sourceCode cpp">type_of</code>, <code class="sourceCode cpp">parent_of</code>, <code class="sourceCode cpp">entity_of</code><a href="#type_of-parent_of-entity_of" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb33-2"><a href="#cb33-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> type_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb33-3"><a href="#cb33-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> parent_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb33-4"><a href="#cb33-4"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> entity_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb33-5"><a href="#cb33-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">r</code> is a reflection designating a typed entity, <code class="sourceCode cpp">type_of<span class="op">(</span>r<span class="op">)</span></code> is a reflection designating its type. Otherwise, <code class="sourceCode cpp">type_of<span class="op">(</span>r<span class="op">)</span></code> produces an invalid reflection.</p>
<p>If <code class="sourceCode cpp">r</code> designates a member of a class or namespace, <code class="sourceCode cpp">parent_of<span class="op">(</span>r<span class="op">)</span></code> is a reflection designating its immediately enclosing class or namespace. Otherwise, <code class="sourceCode cpp">parent_of<span class="op">(</span>r<span class="op">)</span></code> produces an invalid reflection.</p>
<p>If <code class="sourceCode cpp">r</code> designates an alias, <code class="sourceCode cpp">entity_of<span class="op">(</span>r<span class="op">)</span></code> designates the underlying entity. Otherwise, <code class="sourceCode cpp">entity_of<span class="op">(</span>r<span class="op">)</span></code> produces <code class="sourceCode cpp">r</code>.</p>
<h3 data-number="3.4.4" id="template_of-template_arguments_of"><span class="header-section-number">3.4.4</span> <code class="sourceCode cpp">template_of</code>, <code class="sourceCode cpp">template_arguments_of</code><a href="#template_of-template_arguments_of" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb34-2"><a href="#cb34-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> template_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb34-3"><a href="#cb34-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> template_arguments_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb34-4"><a href="#cb34-4"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">r</code> is a reflection designated a type that is a specialization of some template, then <code class="sourceCode cpp">template_of<span class="op">(</span>r<span class="op">)</span></code> is a reflection of that template and <code class="sourceCode cpp">template_arguments_of<span class="op">(</span>r<span class="op">)</span></code> is a vector of the reflections of the template arguments. Otherwise, both yield invalid reflections. In other words, the preconditions on both is that <code class="sourceCode cpp">has_template_arguments<span class="op">(</span>r<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>.</p>
<p>For example:</p>
<blockquote>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v <span class="op">=</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>;</span>
<span id="cb35-2"><a href="#cb35-2"></a><span class="kw">static_assert</span><span class="op">(</span>template_of<span class="op">(</span>type_of<span class="op">(^</span>v<span class="op">))</span> <span class="op">==</span> <span class="op">^</span>std<span class="op">::</span>vector<span class="op">)</span>;</span>
<span id="cb35-3"><a href="#cb35-3"></a><span class="kw">static_assert</span><span class="op">(</span>template_arguments_of<span class="op">(</span>type_of<span class="op">(^</span>v<span class="op">))[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="op">^</span><span class="dt">int</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<h3 data-number="3.4.5" id="members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of"><span class="header-section-number">3.4.5</span> <code class="sourceCode cpp">members_of</code>, <code class="sourceCode cpp">nonstatic_data_members_of</code>, <code class="sourceCode cpp">bases_of</code>, <code class="sourceCode cpp">enumerators_of</code>, <code class="sourceCode cpp">subobjects_of</code><a href="#members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb36-2"><a href="#cb36-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span>Fs<span class="op">&gt;</span></span>
<span id="cb36-3"><a href="#cb36-3"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> members_of<span class="op">(</span>info class_type, Fs <span class="op">...</span>filters<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb36-4"><a href="#cb36-4"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span>Fs<span class="op">&gt;</span></span>
<span id="cb36-5"><a href="#cb36-5"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> nonstatic_data_members_of<span class="op">(</span>info class_type, Fs <span class="op">...</span>filters<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb36-6"><a href="#cb36-6"></a>      <span class="cf">return</span> members_of<span class="op">(</span>class_type, is_nonstatic_data_member, filters<span class="op">...)</span>;</span>
<span id="cb36-7"><a href="#cb36-7"></a>    <span class="op">}</span></span>
<span id="cb36-8"><a href="#cb36-8"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span>Fs<span class="op">&gt;</span></span>
<span id="cb36-9"><a href="#cb36-9"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> bases_of<span class="op">(</span>info class_type, Fs <span class="op">...</span>filters<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb36-10"><a href="#cb36-10"></a>      <span class="cf">return</span> members_of<span class="op">(</span>class_type, is_base, filters<span class="op">...)</span>;</span>
<span id="cb36-11"><a href="#cb36-11"></a>    <span class="op">}</span></span>
<span id="cb36-12"><a href="#cb36-12"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span>Fs<span class="op">&gt;</span></span>
<span id="cb36-13"><a href="#cb36-13"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> enumerators_of<span class="op">(</span>info class_type, Fs <span class="op">...</span>filters<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb36-14"><a href="#cb36-14"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span>Fs<span class="op">&gt;</span></span>
<span id="cb36-15"><a href="#cb36-15"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> subobjects_of<span class="op">(</span>info class_type, Fs <span class="op">...</span>filters<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb36-16"><a href="#cb36-16"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h3 data-number="3.4.6" id="substitute"><span class="header-section-number">3.4.6</span> <code class="sourceCode cpp">substitute</code><a href="#substitute" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb37-2"><a href="#cb37-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> substitute<span class="op">(</span>info templ, span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;</span> args<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb37-3"><a href="#cb37-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Given a reflection for a template and reflections for template arguments that match that template, <code class="sourceCode cpp">substitute</code> returns a reflection for the entity obtains by substituting the given arguments in the template.</p>
<p>For example:</p>
<blockquote>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> substitute<span class="op">(^</span>std<span class="op">::</span>vector, std<span class="op">::</span>vector<span class="op">{^</span><span class="dt">int</span><span class="op">})</span>;</span>
<span id="cb38-2"><a href="#cb38-2"></a><span class="kw">using</span> T <span class="op">=</span> <span class="op">[:</span>r<span class="op">:]</span>; <span class="co">// Ok, T is std::vector&lt;int&gt;</span></span></code></pre></div>
</blockquote>
<p>This process might kick off instantiations outside the immediate context, which can lead to the program being ill-formed. Substitution errors in the immediate context of the template result in an invalid reflection being returned.</p>
<p>Note that the template is only substituted, not instantiated. For example:</p>
<blockquote>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">struct</span> S <span class="op">{</span> <span class="kw">typename</span> T<span class="op">::</span>X x; <span class="op">}</span>;</span>
<span id="cb39-2"><a href="#cb39-2"></a></span>
<span id="cb39-3"><a href="#cb39-3"></a><span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> substitute<span class="op">(^</span>S, std<span class="op">::</span>vector<span class="op">{^</span><span class="dt">int</span><span class="op">})</span>;  <span class="co">// Okay.</span></span>
<span id="cb39-4"><a href="#cb39-4"></a><span class="kw">typename</span><span class="op">[:</span>r<span class="op">:]</span> si;  <span class="co">// Error: T::X is invalid for T = int.</span></span></code></pre></div>
</blockquote>
<h3 data-number="3.4.7" id="entity_reft-value_oft-ptr_to_membert"><span class="header-section-number">3.4.7</span> <code class="sourceCode cpp">entity_ref<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, <code class="sourceCode cpp">ptr_to_member<span class="op">&lt;</span>T<span class="op">&gt;</span></code><a href="#entity_reft-value_oft-ptr_to_membert" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb40-2"><a href="#cb40-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">consteval</span> <span class="kw">auto</span> entity_ref<span class="op">(</span>info var_or_func<span class="op">)</span> <span class="op">-&gt;</span> T<span class="op">&amp;</span>;</span>
<span id="cb40-3"><a href="#cb40-3"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">consteval</span> <span class="kw">auto</span> value_of<span class="op">(</span>info constant_expr<span class="op">)</span> <span class="op">-&gt;</span> T;</span>
<span id="cb40-4"><a href="#cb40-4"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">consteval</span> <span class="kw">auto</span> pointer_to_member<span class="op">(</span>info member<span class="op">)</span> <span class="op">-&gt;</span> T;</span>
<span id="cb40-5"><a href="#cb40-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">r</code> is a reflection of a variable or function of type <code class="sourceCode cpp">T</code>, <code class="sourceCode cpp">entity_ref<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to a reference to that variable or function. Otherwise, <code class="sourceCode cpp">entity_ref<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> is ill-formed.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection for a constant-expression or a constant-valued entity of type <code class="sourceCode cpp">T</code>, <code class="sourceCode cpp">value_of<span class="op">(</span>r<span class="op">)</span></code> evaluates to that constant value. Otherwise, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> is ill-formed.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection for a non-static member or for a constant pointer-to-member value matching type <code class="sourceCode cpp">T</code>, <code class="sourceCode cpp">pointer_to_member<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to a corresonding pointer-to-member value. Otherwise, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> is ill-formed.</p>
<p>These function may feel similar to splicers, but unlike splicers they do not require their operand to be a constant-expression itself. Also unlike splicers, they require knowledge of the type associated with the entity reflected by their operand.</p>
<h3 data-number="3.4.8" id="test_typepred"><span class="header-section-number">3.4.8</span> <code class="sourceCode cpp">test_type<span class="op">&lt;</span>Pred<span class="op">&gt;</span></code><a href="#test_typepred" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb41-2"><a href="#cb41-2"></a>  <span class="kw">auto</span> test_type<span class="op">(</span>info templ, info type<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb41-3"><a href="#cb41-3"></a>    <span class="cf">return</span> test_types<span class="op">(</span>templ, vector<span class="op">{</span>type<span class="op">})</span>;</span>
<span id="cb41-4"><a href="#cb41-4"></a>  <span class="op">}</span></span>
<span id="cb41-5"><a href="#cb41-5"></a></span>
<span id="cb41-6"><a href="#cb41-6"></a>  <span class="kw">auto</span> test_types<span class="op">(</span>info templ, span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;</span> types<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb41-7"><a href="#cb41-7"></a>    <span class="cf">return</span> value_of<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>substitute<span class="op">(</span>templ, types<span class="op">))</span>;</span>
<span id="cb41-8"><a href="#cb41-8"></a>  <span class="op">}</span></span>
<span id="cb41-9"><a href="#cb41-9"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This utility translates existing metaprogramming predicates (expressed as constexpr variable templates) to the reflection domain. For example:</p>
<blockquote>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb42-2"><a href="#cb42-2"></a><span class="kw">static_assert</span><span class="op">(</span>test_type<span class="op">(^</span>std<span class="op">::</span>is_class_v, <span class="op">^</span>S<span class="op">))</span>;</span></code></pre></div>
</blockquote>
<p>An implementation is permitted to recognize standard predicate templates and implement <code class="sourceCode cpp">test_type</code> without actually instantiating the predicate template. In fact, that is recommended practice.</p>
<h3 data-number="3.4.9" id="other-singular-reflection-predicates"><span class="header-section-number">3.4.9</span> Other Singular Reflection Predicates<a href="#other-singular-reflection-predicates" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb43-2"><a href="#cb43-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_public<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-3"><a href="#cb43-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_protected<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-4"><a href="#cb43-4"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_private<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-5"><a href="#cb43-5"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_accessible<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-6"><a href="#cb43-6"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_virtual<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-7"><a href="#cb43-7"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_deleted<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-8"><a href="#cb43-8"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_defaulted<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-9"><a href="#cb43-9"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_explicit<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-10"><a href="#cb43-10"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_override<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-11"><a href="#cb43-11"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_pure_virtual<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-12"><a href="#cb43-12"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> has_static_storage_duration<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-13"><a href="#cb43-13"></a></span>
<span id="cb43-14"><a href="#cb43-14"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_nsdm<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-15"><a href="#cb43-15"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_base<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-16"><a href="#cb43-16"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_namespace<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-17"><a href="#cb43-17"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_function<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-18"><a href="#cb43-18"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_static<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-19"><a href="#cb43-19"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_variable<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-20"><a href="#cb43-20"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_type<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-21"><a href="#cb43-21"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_alias<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-22"><a href="#cb43-22"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_incomplete_type<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-23"><a href="#cb43-23"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_template<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-24"><a href="#cb43-24"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_function_template<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-25"><a href="#cb43-25"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_variable_template<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-26"><a href="#cb43-26"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_class_template<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-27"><a href="#cb43-27"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_alias_template<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-28"><a href="#cb43-28"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> has_template_arguments<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb43-29"><a href="#cb43-29"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h3 data-number="3.4.10" id="reflect_value"><span class="header-section-number">3.4.10</span> <code class="sourceCode cpp">reflect_value</code><a href="#reflect_value" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb44-2"><a href="#cb44-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">consteval</span> <span class="kw">auto</span> reflect_value<span class="op">(</span>T value<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb44-3"><a href="#cb44-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This metafunction produces a reflection representing the constant value of the operand.</p>
<h3 data-number="3.4.11" id="nsdm_description-synth_struct-synth_union"><span class="header-section-number">3.4.11</span> <code class="sourceCode cpp">nsdm_description</code>, <code class="sourceCode cpp">synth_struct</code>, <code class="sourceCode cpp">synth_union</code><a href="#nsdm_description-synth_struct-synth_union" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb45-2"><a href="#cb45-2"></a>  <span class="kw">struct</span> nsdm_field_args <span class="op">{</span></span>
<span id="cb45-3"><a href="#cb45-3"></a>    optional<span class="op">&lt;</span>string_view<span class="op">&gt;</span> name;</span>
<span id="cb45-4"><a href="#cb45-4"></a>    optional<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> alignment;</span>
<span id="cb45-5"><a href="#cb45-5"></a>    optional<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> width;</span>
<span id="cb45-6"><a href="#cb45-6"></a>  <span class="op">}</span>;</span>
<span id="cb45-7"><a href="#cb45-7"></a></span>
<span id="cb45-8"><a href="#cb45-8"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> nsdm_description<span class="op">(</span>info type, nsdm_field_args args <span class="op">=</span> <span class="op">{})</span> <span class="op">-&gt;</span> info;</span>
<span id="cb45-9"><a href="#cb45-9"></a></span>
<span id="cb45-10"><a href="#cb45-10"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> synth_struct<span class="op">(</span>span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb45-11"><a href="#cb45-11"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> synth_union<span class="op">(</span>span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb45-12"><a href="#cb45-12"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">nsdm_description</code> creates a reflection that describes a non-static data member of given type. Optional alignment, bit-field-width, and name can be provided as well. If <code class="sourceCode cpp">type</code> does not designated a valid data member type, an invalid reflection is produced. If no <code class="sourceCode cpp">name</code> is provided, the name of the non-static data member is unspecified. Note that the reflection obtained from <code class="sourceCode cpp">nsdm_description</code> is <em>not</em> the reflection of a non-static data member itself; it only encapsulates the information needed to synthesize such a data member. In particular, metafunctions like <code class="sourceCode cpp">name_of</code>, <code class="sourceCode cpp">type_of</code>, and <code class="sourceCode cpp">parent_of</code> are not applicable to the result of an <code class="sourceCode cpp">nsdm_description</code>.</p>
<p><code class="sourceCode cpp">synth_struct</code> and <code class="sourceCode cpp">synth_union</code> take a range of NSDM descriptions and return a reflection that denotes a struct and union, respectively, comprised of corresponding non-static data members.</p>
<p>For example:</p>
<blockquote>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> T <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>synth_struct<span class="op">({</span></span>
<span id="cb46-2"><a href="#cb46-2"></a>  nsdm_description<span class="op">(^</span><span class="dt">int</span><span class="op">)</span>,</span>
<span id="cb46-3"><a href="#cb46-3"></a>  nsdm_description<span class="op">(^</span><span class="dt">char</span><span class="op">)</span>,</span>
<span id="cb46-4"><a href="#cb46-4"></a>  nsdm_description<span class="op">(^</span><span class="dt">double</span><span class="op">)</span>,</span>
<span id="cb46-5"><a href="#cb46-5"></a><span class="op">})</span>;</span>
<span id="cb46-6"><a href="#cb46-6"></a></span>
<span id="cb46-7"><a href="#cb46-7"></a><span class="co">// T is a reflection of the type</span></span>
<span id="cb46-8"><a href="#cb46-8"></a><span class="co">// struct {</span></span>
<span id="cb46-9"><a href="#cb46-9"></a><span class="co">//   int <em>_0</em>;</span></span>
<span id="cb46-10"><a href="#cb46-10"></a><span class="co">//   char <em>_1</em>;</span></span>
<span id="cb46-11"><a href="#cb46-11"></a><span class="co">//   double <em>_2</em>;</span></span>
<span id="cb46-12"><a href="#cb46-12"></a><span class="co">// }</span></span>
<span id="cb46-13"><a href="#cb46-13"></a></span>
<span id="cb46-14"><a href="#cb46-14"></a><span class="kw">constexpr</span> <span class="kw">auto</span> U <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>synth_struct<span class="op">({</span></span>
<span id="cb46-15"><a href="#cb46-15"></a>  nsdm_description<span class="op">(^</span><span class="dt">int</span>, <span class="op">{.</span>name<span class="op">=</span><span class="st">&quot;i&quot;</span>, <span class="op">.</span>align<span class="op">=</span><span class="dv">64</span><span class="op">})</span>,</span>
<span id="cb46-16"><a href="#cb46-16"></a>  nsdm_description<span class="op">(^</span><span class="dt">int</span>, <span class="op">{.</span>name<span class="op">=</span><span class="st">&quot;j&quot;</span>, <span class="op">.</span>align<span class="op">=</span><span class="dv">64</span><span class="op">})</span>,</span>
<span id="cb46-17"><a href="#cb46-17"></a><span class="op">})</span>;</span>
<span id="cb46-18"><a href="#cb46-18"></a></span>
<span id="cb46-19"><a href="#cb46-19"></a><span class="co">// U is a reflection of the type</span></span>
<span id="cb46-20"><a href="#cb46-20"></a><span class="co">// struct {</span></span>
<span id="cb46-21"><a href="#cb46-21"></a><span class="co">//   alignas(64) int i;</span></span>
<span id="cb46-22"><a href="#cb46-22"></a><span class="co">//   alignas(64) int j;</span></span>
<span id="cb46-23"><a href="#cb46-23"></a><span class="co">// }</span></span></code></pre></div>
</blockquote>
<h3 data-number="3.4.12" id="data-layout-reflection"><span class="header-section-number">3.4.12</span> Data Layout Reflection<a href="#data-layout-reflection" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb47-2"><a href="#cb47-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> offset_of<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">size_t</span>;</span>
<span id="cb47-3"><a href="#cb47-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> size_of<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">size_t</span>;</span>
<span id="cb47-4"><a href="#cb47-4"></a></span>
<span id="cb47-5"><a href="#cb47-5"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> bit_offset_of<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">size_t</span>;</span>
<span id="cb47-6"><a href="#cb47-6"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> bit_size_of<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">size_t</span>;</span>
<span id="cb47-7"><a href="#cb47-7"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">4</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-N3980">
<p>[N3980] H. Hinnant, V. Falco, J. Byteway. 2014-05-24. Types don’t know #. <br />
<a href="https://wg21.link/n3980">https://wg21.link/n3980</a></p>
</div>
<div id="ref-P0784R7">
<p>[P0784R7] Daveed Vandevoorde, Peter Dimov,Louis Dionne, Nina Ranns, Richard Smith, Daveed Vandevoorde. 2019-07-22. More constexpr containers. <br />
<a href="https://wg21.link/p0784r7">https://wg21.link/p0784r7</a></p>
</div>
<div id="ref-P1061R5">
<p>[P1061R5] Barry Revzin, Jonathan Wakely. 2023-05-18. Structured Bindings can introduce a Pack. <br />
<a href="https://wg21.link/p1061r5">https://wg21.link/p1061r5</a></p>
</div>
<div id="ref-P1240R2">
<p>[P1240R2] Daveed Vandevoorde, Wyatt Childers, Andrew Sutton, Faisal Vali. 2022-01-14. Scalable Reflection. <br />
<a href="https://wg21.link/p1240r2">https://wg21.link/p1240r2</a></p>
</div>
<div id="ref-P1306R1">
<p>[P1306R1] Andrew Sutton, Sam Goodrick, Daveed Vandevoorde. 2019-01-21. Expansion statements. <br />
<a href="https://wg21.link/p1306r1">https://wg21.link/p1306r1</a></p>
</div>
<div id="ref-P1974R0">
<p>[P1974R0] Jeff Snyder, Louis Dionne, Daveed Vandevoorde. 2020-05-15. Non-transient constexpr allocation using propconst. <br />
<a href="https://wg21.link/p1974r0">https://wg21.link/p1974r0</a></p>
</div>
<div id="ref-P2237R0">
<p>[P2237R0] Andrew Sutton. 2020-10-15. Metaprogramming. <br />
<a href="https://wg21.link/p2237r0">https://wg21.link/p2237r0</a></p>
</div>
<div id="ref-P2670R1">
<p>[P2670R1] Barry Revzin. 2023-02-03. Non-transient constexpr allocation. <br />
<a href="https://wg21.link/p2670r1">https://wg21.link/p2670r1</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
