<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-02-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>P2996R2</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-02-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, LEWG<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>
      Dan Katz<br>&lt;<a href="mailto:dkatz85@bloomberg.net" class="email">dkatz85@bloomberg.net</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="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#notable-additions-to-p1240"><span class="toc-section-number">2.1</span> Notable Additions to P1240<span></span></a></li>
<li><a href="#why-a-single-opaque-reflection-type"><span class="toc-section-number">2.2</span> Why a single opaque reflection type?<span></span></a></li>
<li><a href="#implementation-status"><span class="toc-section-number">2.3</span> Implementation Status<span></span></a></li>
</ul></li>
<li><a href="#examples"><span class="toc-section-number">3</span> Examples<span></span></a>
<ul>
<li><a href="#back-and-forth"><span class="toc-section-number">3.1</span> Back-And-Forth<span></span></a></li>
<li><a href="#selecting-members"><span class="toc-section-number">3.2</span> Selecting Members<span></span></a></li>
<li><a href="#list-of-types-to-list-of-sizes"><span class="toc-section-number">3.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">3.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">3.5</span> Getting Class Layout<span></span></a></li>
<li><a href="#enum-to-string"><span class="toc-section-number">3.6</span> Enum to String<span></span></a></li>
<li><a href="#parsing-command-line-options"><span class="toc-section-number">3.7</span> Parsing Command-Line Options<span></span></a></li>
<li><a href="#a-simple-tuple-type"><span class="toc-section-number">3.8</span> A Simple Tuple Type<span></span></a></li>
<li><a href="#a-simple-variant-type"><span class="toc-section-number">3.9</span> A Simple Variant Type<span></span></a></li>
<li><a href="#struct-to-struct-of-arrays"><span class="toc-section-number">3.10</span> Struct to Struct of Arrays<span></span></a></li>
<li><a href="#parsing-command-line-options-ii"><span class="toc-section-number">3.11</span> Parsing Command-Line Options II<span></span></a></li>
<li><a href="#a-universal-formatter"><span class="toc-section-number">3.12</span> A Universal Formatter<span></span></a></li>
<li><a href="#implementing-member-wise-hash_append"><span class="toc-section-number">3.13</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">3.14</span> Converting a Struct to a Tuple<span></span></a></li>
<li><a href="#named-tuple"><span class="toc-section-number">3.15</span> Named Tuple<span></span></a></li>
<li><a href="#compile-time-ticket-counter"><span class="toc-section-number">3.16</span> Compile-Time Ticket Counter<span></span></a></li>
<li><a href="#emulating-typeful-reflection"><span class="toc-section-number">3.17</span> Emulating typeful reflection<span></span></a></li>
</ul></li>
<li><a href="#proposed-features"><span class="toc-section-number">4</span> Proposed Features<span></span></a>
<ul>
<li><a href="#the-reflection-operator"><span class="toc-section-number">4.1</span> The Reflection Operator (<code class="sourceCode cpp"><span class="op">^</span></code>)<span></span></a>
<ul>
<li><a href="#syntax-discussion"><span class="toc-section-number">4.1.1</span> Syntax discussion<span></span></a></li>
</ul></li>
<li><a href="#splicers"><span class="toc-section-number">4.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">4.2.1</span> Range Splicers<span></span></a></li>
<li><a href="#syntax-discussion-1"><span class="toc-section-number">4.2.2</span> Syntax discussion<span></span></a></li>
</ul></li>
<li><a href="#stdmetainfo"><span class="toc-section-number">4.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">4.4</span> Metafunctions<span></span></a>
<ul>
<li><a href="#constant-evaluation-order"><span class="toc-section-number">4.4.1</span> Constant evaluation order<span></span></a></li>
<li><a href="#error-handling-in-reflection"><span class="toc-section-number">4.4.2</span> Error-Handling in Reflection<span></span></a></li>
<li><a href="#handling-aliases"><span class="toc-section-number">4.4.3</span> Handling Aliases<span></span></a></li>
<li><a href="#freestanding-implementations"><span class="toc-section-number">4.4.4</span> Freestanding implementations<span></span></a></li>
<li><a href="#synopsis"><span class="toc-section-number">4.4.5</span> Synopsis<span></span></a></li>
<li><a href="#name_of-display_name_of-source_location_of"><span class="toc-section-number">4.4.6</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-dealias"><span class="toc-section-number">4.4.7</span> <code class="sourceCode cpp">type_of</code>, <code class="sourceCode cpp">parent_of</code>, <code class="sourceCode cpp">dealias</code><span></span></a></li>
<li><a href="#template_of-template_arguments_of"><span class="toc-section-number">4.4.8</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-static_data_members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of"><span class="toc-section-number">4.4.9</span> <code class="sourceCode cpp">members_of</code>, <code class="sourceCode cpp">static_data_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">4.4.10</span> <code class="sourceCode cpp">substitute</code><span></span></a></li>
<li><a href="#reflect_invoke"><span class="toc-section-number">4.4.11</span> <code class="sourceCode cpp">reflect_invoke</code><span></span></a></li>
<li><a href="#value_oft"><span class="toc-section-number">4.4.12</span> <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#test_type-test_types"><span class="toc-section-number">4.4.13</span> <code class="sourceCode cpp">test_type</code>, <code class="sourceCode cpp">test_types</code><span></span></a></li>
<li><a href="#reflect_value"><span class="toc-section-number">4.4.14</span> <code class="sourceCode cpp">reflect_value</code><span></span></a></li>
<li><a href="#data_member_spec-define_class"><span class="toc-section-number">4.4.15</span> <code class="sourceCode cpp">data_member_spec</code>, <code class="sourceCode cpp">define_class</code><span></span></a></li>
<li><a href="#data-layout-reflection"><span class="toc-section-number">4.4.16</span> Data Layout Reflection<span></span></a></li>
<li><a href="#other-type-traits"><span class="toc-section-number">4.4.17</span> Other Type Traits<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#proposed-wording"><span class="toc-section-number">5</span> Proposed Wording<span></span></a>
<ul>
<li><a href="#language"><span class="toc-section-number">5.1</span> Language<span></span></a>
<ul>
<li><a href="#lex.phases-phases-of-translation"><span class="toc-section-number">5.1.1</span> [lex.phases] Phases of translation<span></span></a></li>
<li><a href="#lex.pptoken-preprocessing-tokens"><span class="toc-section-number">5.1.2</span> [lex.pptoken] Preprocessing tokens<span></span></a></li>
<li><a href="#lex.operators-operators-and-punctuators"><span class="toc-section-number">5.1.3</span> [lex.operators] Operators and punctuators<span></span></a></li>
<li><a href="#basic.types.general"><span class="toc-section-number">5.1.4</span> [basic.types.general]<span></span></a></li>
<li><a href="#basic.fundamental-fundamental-types"><span class="toc-section-number">5.1.5</span> [basic.fundamental] Fundamental types<span></span></a></li>
<li><a href="#basic.lookup.argdep-argument-dependent-name-lookup"><span class="toc-section-number">5.1.6</span> [basic.lookup.argdep] Argument-dependent name lookup<span></span></a></li>
<li><a href="#basic.lookup.qual.general-general"><span class="toc-section-number">5.1.7</span> [basic.lookup.qual.general] General<span></span></a></li>
<li><a href="#expr.prim-primary-expressions"><span class="toc-section-number">5.1.8</span> [expr.prim] Primary expressions<span></span></a></li>
<li><a href="#expr.prim.id.qual-qualified-names"><span class="toc-section-number">5.1.9</span> [expr.prim.id.qual] Qualified names<span></span></a></li>
<li><a href="#expr.prim.splice-expression-splicing"><span class="toc-section-number">5.1.10</span> [expr.prim.splice] Expression splicing<span></span></a></li>
<li><a href="#expr.unary.general"><span class="toc-section-number">5.1.11</span> [expr.unary.general]<span></span></a></li>
<li><a href="#expr.reflect-the-reflection-operator"><span class="toc-section-number">5.1.12</span> [expr.reflect] The reflection operator<span></span></a></li>
<li><a href="#expr.eq-equality-operators"><span class="toc-section-number">5.1.13</span> [expr.eq] Equality Operators<span></span></a></li>
<li><a href="#expr.const-constant-expressions"><span class="toc-section-number">5.1.14</span> [expr.const] Constant Expressions<span></span></a></li>
<li><a href="#dcl.typedef-the-typedef-specifier"><span class="toc-section-number">5.1.15</span> [dcl.typedef] The <code class="sourceCode cpp"><span class="kw">typedef</span></code> specifier<span></span></a></li>
<li><a href="#dcl.attr.grammar-attribute-syntax-and-semantics"><span class="toc-section-number">5.1.16</span> [dcl.attr.grammar] Attribute syntax and semantics<span></span></a></li>
<li><a href="#temp.names-names-of-template-specializations"><span class="toc-section-number">5.1.17</span> [temp.names] Names of template specializations<span></span></a></li>
<li><a href="#temp.arg.general-general"><span class="toc-section-number">5.1.18</span> [temp.arg.general] General<span></span></a></li>
<li><a href="#temp.arg.type-template-type-arguments"><span class="toc-section-number">5.1.19</span> [temp.arg.type] Template type arguments<span></span></a></li>
<li><a href="#temp.arg.nontype-template-non-type-arguments"><span class="toc-section-number">5.1.20</span> [temp.arg.nontype] Template non-type arguments<span></span></a></li>
<li><a href="#temp.arg.template-template-template-arguments"><span class="toc-section-number">5.1.21</span> [temp.arg.template] Template template arguments<span></span></a></li>
</ul></li>
<li><a href="#library"><span class="toc-section-number">5.2</span> Library<span></span></a>
<ul>
<li><a href="#over.built-built-in-operators"><span class="toc-section-number">5.2.1</span> [over.built] Built-in operators<span></span></a></li>
<li><a href="#header-meta-synopsis"><span class="toc-section-number">5.2.2</span> Header <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code> synopsis<span></span></a></li>
<li><a href="#meta.reflection.names-reflection-names-and-locations"><span class="toc-section-number">5.2.3</span> [meta.reflection.names] Reflection names and locations<span></span></a></li>
<li><a href="#meta.reflection.queries-reflection-queries"><span class="toc-section-number">5.2.4</span> [meta.reflection.queries] Reflection queries<span></span></a></li>
<li><a href="#meta.reflection.member.queries-reflection-member-queries"><span class="toc-section-number">5.2.5</span> [meta.reflection.member.queries], Reflection member queries<span></span></a></li>
<li><a href="#meta.reflection.unary-unary-type-traits"><span class="toc-section-number">5.2.6</span> [meta.reflection.unary] Unary type traits<span></span></a>
<ul>
<li><a href="#meta.reflection.unary.cat-primary-type-categories"><span class="toc-section-number">5.2.6.1</span> [meta.reflection.unary.cat] Primary type categories<span></span></a></li>
<li><a href="#meta.reflection.unary.comp-composite-type-categories"><span class="toc-section-number">5.2.6.2</span> [meta.reflection.unary.comp] Composite type categories<span></span></a></li>
<li><a href="#meta.reflection.unary.prop-type-properties"><span class="toc-section-number">5.2.6.3</span> [meta.reflection.unary.prop] Type properties<span></span></a></li>
<li><a href="#meta.reflection.unary.prop.query-type-property-queries"><span class="toc-section-number">5.2.6.4</span> [meta.reflection.unary.prop.query] Type property queries<span></span></a></li>
</ul></li>
<li><a href="#meta.reflection.rel-type-relations"><span class="toc-section-number">5.2.7</span> [meta.reflection.rel], Type relations<span></span></a></li>
<li><a href="#meta.reflection.trans-transformations-between-types"><span class="toc-section-number">5.2.8</span> [meta.reflection.trans], Transformations between types<span></span></a>
<ul>
<li><a href="#meta.reflection.trans.cv-const-volatile-modifications"><span class="toc-section-number">5.2.8.1</span> [meta.reflection.trans.cv], Const-volatile modifications<span></span></a></li>
<li><a href="#meta.reflection.trans.ref-reference-modifications"><span class="toc-section-number">5.2.8.2</span> [meta.reflection.trans.ref], Reference modifications<span></span></a></li>
<li><a href="#meta.reflection.trans.sign-sign-modifications"><span class="toc-section-number">5.2.8.3</span> [meta.reflection.trans.sign], Sign modifications<span></span></a></li>
<li><a href="#meta.reflection.trans.arr-array-modifications"><span class="toc-section-number">5.2.8.4</span> [meta.reflection.trans.arr], Array modifications<span></span></a></li>
<li><a href="#meta.reflection.trans.ptr-pointer-modifications"><span class="toc-section-number">5.2.8.5</span> [meta.reflection.trans.ptr], Pointer modifications<span></span></a></li>
<li><a href="#meta.reflection.trans.other-other-transformations"><span class="toc-section-number">5.2.8.6</span> [meta.reflection.trans.other], Other transformations<span></span></a></li>
</ul></li>
</ul></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P2996R1">[<a href="#ref-P2996R1" role="doc-biblioref">P2996R1</a>]</span>, several changes to the overall library API:</p>
<ul>
<li>added <code class="sourceCode cpp">qualified_name_of</code> (to partner with <code class="sourceCode cpp">name_of</code>)</li>
<li>removed <code class="sourceCode cpp">is_static</code> for being ambiguous, added <code class="sourceCode cpp">has_internal_linkage</code> (and <code class="sourceCode cpp">has_linkage</code> and <code class="sourceCode cpp">has_external_linkage</code>) and <code class="sourceCode cpp">is_static_member</code> instead</li>
<li>added <code class="sourceCode cpp">is_class_member</code>, <code class="sourceCode cpp">is_namespace_member</code>, and <code class="sourceCode cpp">is_concept</code></li>
<li>added <code class="sourceCode cpp">reflect_invoke</code></li>
<li>added <a href="#other-type-traits">all the type traits</a></li>
</ul>
<p>Other paper changes: * some updates to examples, including a new examples which add a <a href="#named-tuple">named tuple</a> and <a href="#emulating-typeful-reflection">emulate typeful reflection</a>. * more discussion of syntax, constant evaluation order, aliases, and freestanding. * adding lots of wording</p>
<p>Since <span class="citation" data-cites="P2996R0">[<a href="#ref-P2996R0" role="doc-biblioref">P2996R0</a>]</span>:</p>
<ul>
<li>added links to Compiler Explorer demonstrating just about all of the examples</li>
<li>respecified <code class="sourceCode cpp">synth_struct</code> to <code class="sourceCode cpp">define_class</code></li>
<li>respecified a few metafunctions to be functions instead of function templates</li>
<li>introduced section on error handling mechanism and our preference for exceptions (removing invalid reflections)</li>
<li>added ticket counter and variant examples</li>
<li>collapsed <code class="sourceCode cpp">entity_ref</code> and <code class="sourceCode cpp">pointer_to_member</code> into <code class="sourceCode cpp">value_of</code></li>
</ul>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>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>(Note that this aims at something a little broader than pure “reflection”. We not only want to observe the structure of the program: We also want to ease generating code that depends on those observations. That combination is sometimes referred to as “reflective metaprogramming”, but within WG21 discussion the term “reflection” has often been used informally to refer to the same general idea.)</p>
<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="2.1" id="notable-additions-to-p1240"><span class="header-section-number">2.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="2.2" id="why-a-single-opaque-reflection-type"><span class="header-section-number">2.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 a 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>
<h2 data-number="2.3" id="implementation-status"><span class="header-section-number">2.3</span> Implementation Status<a href="#implementation-status" class="self-link"></a></h2>
<p>Lock3 implemented the equivalent of much that is proposed here in a fork of Clang (specifically, it worked with the P1240 proposal, but also included several other capabilities including a first-class injection mechanism).</p>
<p>EDG has an ongoing implementation of this proposal that is currently available on Compiler Explorer (thank you, Matt Godbolt). Nearly all of the examples below have links to compiler explorer demonstrating them.</p>
<p>The implementation is not complete (notably, for debugging purposes, <code class="sourceCode cpp">name_of<span class="op">(^</span><span class="dt">int</span><span class="op">)</span></code> yields an empty string and <code class="sourceCode cpp">name_of<span class="op">(^</span>std<span class="op">::</span>optional<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;)</span></code> yields <code class="sourceCode cpp"><span class="st">&quot;optional&quot;</span></code>, neither of which are what we want). The implementation will evolve along with this paper. The EDG implementation also lacks some of the other language features we would like to be able to take advantage of. In particular, it does not support expansion statements. A workaround that will be used in the linked implementations of examples is the following facility:</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">namespace</span> __impl <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span><span class="op">...</span> vals<span class="op">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>  <span class="kw">struct</span> replicator_type <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> F<span class="op">&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>      <span class="kw">constexpr</span> <span class="dt">void</span> <span class="kw">operator</span><span class="op">&gt;&gt;(</span>F body<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6"></a>        <span class="op">(</span>body<span class="op">.</span><span class="kw">template</span> <span class="kw">operator</span><span class="op">()&lt;</span>vals<span class="op">&gt;()</span>, <span class="op">...)</span>;</span>
<span id="cb1-7"><a href="#cb1-7"></a>      <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8"></a>  <span class="op">}</span>;</span>
<span id="cb1-9"><a href="#cb1-9"></a></span>
<span id="cb1-10"><a href="#cb1-10"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span><span class="op">...</span> vals<span class="op">&gt;</span></span>
<span id="cb1-11"><a href="#cb1-11"></a>  replicator_type<span class="op">&lt;</span>vals<span class="op">...&gt;</span> replicator <span class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="op">}</span></span>
<span id="cb1-13"><a href="#cb1-13"></a></span>
<span id="cb1-14"><a href="#cb1-14"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> R<span class="op">&gt;</span></span>
<span id="cb1-15"><a href="#cb1-15"></a><span class="kw">consteval</span> <span class="kw">auto</span> expand<span class="op">(</span>R range<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-16"><a href="#cb1-16"></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> args;</span>
<span id="cb1-17"><a href="#cb1-17"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> r <span class="op">:</span> range<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-18"><a href="#cb1-18"></a>    args<span class="op">.</span>push_back<span class="op">(</span>reflect_value<span class="op">(</span>r<span class="op">))</span>;</span>
<span id="cb1-19"><a href="#cb1-19"></a>  <span class="op">}</span></span>
<span id="cb1-20"><a href="#cb1-20"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>__impl<span class="op">::</span>replicator, args<span class="op">)</span>;</span>
<span id="cb1-21"><a href="#cb1-21"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Used like:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>With expansion statements</strong>
</div></th>
<th><div style="text-align:center">
<strong>With <code class="sourceCode cpp">expand</code> workaround</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-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="cb2-3"><a href="#cb2-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="cb2-4"><a href="#cb2-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>enumerators_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-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="cb2-6"><a href="#cb2-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="cb2-7"><a href="#cb2-7"></a>    <span class="op">}</span></span>
<span id="cb2-8"><a href="#cb2-8"></a>  <span class="op">}</span></span>
<span id="cb2-9"><a href="#cb2-9"></a></span>
<span id="cb2-10"><a href="#cb2-10"></a>  <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="op">}</span></span></code></pre></div></td>
<td><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">template</span><span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-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="cb3-3"><a href="#cb3-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="cb3-4"><a href="#cb3-4"></a>  std<span class="op">::</span>string result <span class="op">=</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb3-5"><a href="#cb3-5"></a>  <span class="op">[:</span>expand<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>enumerators_of<span class="op">(^</span>E<span class="op">)):]</span> <span class="op">&gt;&gt;</span> <span class="op">[&amp;]&lt;</span><span class="kw">auto</span> e<span class="op">&gt;{</span></span>
<span id="cb3-6"><a href="#cb3-6"></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="cb3-7"><a href="#cb3-7"></a>      result <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="cb3-8"><a href="#cb3-8"></a>    <span class="op">}</span></span>
<span id="cb3-9"><a href="#cb3-9"></a>  <span class="op">}</span>;</span>
<span id="cb3-10"><a href="#cb3-10"></a>  <span class="cf">return</span> result;</span>
<span id="cb3-11"><a href="#cb3-11"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="examples"><span class="header-section-number">3</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="3.1" id="back-and-forth"><span class="header-section-number">3.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="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-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="cb4-2"><a href="#cb4-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="cb4-3"><a href="#cb4-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 (i.e., in what the standard calls <em>type-only contexts</em>). For example:</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">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>
<p><a href="https://godbolt.org/z/13anqE1Pa">On Compiler Explorer</a>.</p>
<h2 data-number="3.2" id="selecting-members"><span class="header-section-number">3.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:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">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="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-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="cb6-4"><a href="#cb6-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="cb6-5"><a href="#cb6-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="cb6-6"><a href="#cb6-6"></a><span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7"></a></span>
<span id="cb6-8"><a href="#cb6-8"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb6-9"><a href="#cb6-9"></a>  S s<span class="op">{</span><span class="dv">0</span>, <span class="dv">0</span><span class="op">}</span>;</span>
<span id="cb6-10"><a href="#cb6-10"></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="cb6-11"><a href="#cb6-11"></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 (member_number(5) is not a constant).</span></span>
<span id="cb6-12"><a href="#cb6-12"></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>
<p><a href="https://godbolt.org/z/vT4rbva7M">On Compiler Explorer</a></p>
<p>Note that a “member access splice” like <code class="sourceCode cpp">s<span class="op">.[:</span>member_number<span class="op">(</span><span class="dv">1</span><span class="op">):]</span></code> is a more direct member access mechanism than the traditional syntax. It doesn’t involve member name lookup, access checking, or — if the spliced reflection value denotes a member function — overload resolution.</p>
<p>This proposal includes a number of consteval “metafunctions” that enable the introspection of various language constructs. Among those metafunctions is <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>nonstatic_data_members_of</code> which returns a vector of reflection values that describe the nonstatic members of a given type. We could thus rewrite the above example as:</p>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">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="cb7-2"><a href="#cb7-2"></a></span>
<span id="cb7-3"><a href="#cb7-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="cb7-4"><a href="#cb7-4"></a>  <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>nonstatic_data_members_of<span class="op">(^</span>S<span class="op">)[</span>n<span class="op">]</span>;</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="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-8"><a href="#cb7-8"></a>  S s<span class="op">{</span><span class="dv">0</span>, <span class="dv">0</span><span class="op">}</span>;</span>
<span id="cb7-9"><a href="#cb7-9"></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="cb7-10"><a href="#cb7-10"></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 (member_number(5) is not a constant).</span></span>
<span id="cb7-11"><a href="#cb7-11"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/Wb1vx7jqb">On Compiler Explorer</a></p>
<p>This proposal specifies that namespace <code class="sourceCode cpp">std<span class="op">::</span>meta</code> is associated with the reflection type (<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>); the <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span></code> qualification can therefore be omitted in the example above.</p>
<p>Another frequently-useful metafunction is <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>name_of</code>, which returns a <code class="sourceCode cpp">std<span class="op">::</span>string_view</code> describing the unqualified name of an entity denoted by a given reflection value. With such a facility, we could conceivably access nonstatic data members “by string”:</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">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="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="kw">consteval</span> <span class="kw">auto</span> member_named<span class="op">(</span>std<span class="op">::</span>string_view name<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-4"><a href="#cb8-4"></a>  <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info field <span class="op">:</span> nonstatic_data_members_of<span class="op">(^</span>S<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>name_of<span class="op">(</span>field<span class="op">)</span> <span class="op">==</span> name<span class="op">)</span> <span class="cf">return</span> field;</span>
<span id="cb8-6"><a href="#cb8-6"></a>  <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>
<span id="cb8-9"><a href="#cb8-9"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-10"><a href="#cb8-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="cb8-11"><a href="#cb8-11"></a>  s<span class="op">.[:</span>member_named<span class="op">(</span><span class="st">&quot;j&quot;</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="cb8-12"><a href="#cb8-12"></a>  s<span class="op">.[:</span>member_named<span class="op">(</span><span class="st">&quot;x&quot;</span><span class="op">):]</span> <span class="op">=</span> <span class="dv">0</span>;   <span class="co">// Error (member_named(&quot;x&quot;) is not a constant).</span></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/dvYoreK9E">On Compiler Explorer</a></p>
<h2 data-number="3.3" id="list-of-types-to-list-of-sizes"><span class="header-section-number">3.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="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-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="cb9-2"><a href="#cb9-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="cb9-3"><a href="#cb9-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="cb9-4"><a href="#cb9-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="cb9-5"><a href="#cb9-5"></a>  <span class="cf">return</span> r;</span>
<span id="cb9-6"><a href="#cb9-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="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">class</span><span class="op">...&gt;</span> <span class="kw">struct</span> list <span class="op">{}</span>;</span>
<span id="cb10-2"><a href="#cb10-2"></a></span>
<span id="cb10-3"><a href="#cb10-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="cb10-4"><a href="#cb10-4"></a></span>
<span id="cb10-5"><a href="#cb10-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="cb10-6"><a href="#cb10-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="cb10-7"><a href="#cb10-7"></a><span class="op">}(</span>types<span class="op">{})</span>;</span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/4xz9Wsa8f">On Compiler Explorer</a>.</p>
<h2 data-number="3.4" id="implementing-make_integer_sequence"><span class="header-section-number">3.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="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="pp">#include </span><span class="im">&lt;utility&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3"></a></span>
<span id="cb11-4"><a href="#cb11-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="cb11-5"><a href="#cb11-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="cb11-6"><a href="#cb11-6"></a>  std<span class="op">::</span>vector args<span class="op">{^</span>T<span class="op">}</span>;</span>
<span id="cb11-7"><a href="#cb11-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="cb11-8"><a href="#cb11-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="cb11-9"><a href="#cb11-9"></a>  <span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-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="cb11-11"><a href="#cb11-11"></a><span class="op">}</span></span>
<span id="cb11-12"><a href="#cb11-12"></a></span>
<span id="cb11-13"><a href="#cb11-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="cb11-14"><a href="#cb11-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>
<p><a href="https://godbolt.org/z/bvPeqvaK5">On Compiler Explorer</a>.</p>
<p>Note that the memoization implicit in the template substitution process still applies. So having multiple uses of, e.g., <code class="sourceCode cpp">make_integer_sequence<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">20</span><span class="op">&gt;</span></code> will only involve one evaluation of <code class="sourceCode cpp">make_integer_seq_refl<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;(</span><span class="dv">20</span><span class="op">)</span></code>.</p>
<h2 data-number="3.5" id="getting-class-layout"><span class="header-section-number">3.5</span> Getting Class Layout<a href="#getting-class-layout" 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="kw">struct</span> member_descriptor</span>
<span id="cb12-2"><a href="#cb12-2"></a><span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3"></a>  std<span class="op">::</span><span class="dt">size_t</span> offset;</span>
<span id="cb12-4"><a href="#cb12-4"></a>  std<span class="op">::</span><span class="dt">size_t</span> size;</span>
<span id="cb12-5"><a href="#cb12-5"></a><span class="op">}</span>;</span>
<span id="cb12-6"><a href="#cb12-6"></a></span>
<span id="cb12-7"><a href="#cb12-7"></a><span class="co">// returns std::array&lt;member_descriptor, N&gt;</span></span>
<span id="cb12-8"><a href="#cb12-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="cb12-9"><a href="#cb12-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="cb12-10"><a href="#cb12-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="cb12-11"><a href="#cb12-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="cb12-12"><a href="#cb12-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="cb12-13"><a href="#cb12-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="cb12-14"><a href="#cb12-14"></a>  <span class="op">}</span></span>
<span id="cb12-15"><a href="#cb12-15"></a>  <span class="cf">return</span> layout;</span>
<span id="cb12-16"><a href="#cb12-16"></a><span class="op">}</span></span>
<span id="cb12-17"><a href="#cb12-17"></a></span>
<span id="cb12-18"><a href="#cb12-18"></a><span class="kw">struct</span> X</span>
<span id="cb12-19"><a href="#cb12-19"></a><span class="op">{</span></span>
<span id="cb12-20"><a href="#cb12-20"></a>    <span class="dt">char</span> a;</span>
<span id="cb12-21"><a href="#cb12-21"></a>    <span class="dt">int</span> b;</span>
<span id="cb12-22"><a href="#cb12-22"></a>    <span class="dt">double</span> c;</span>
<span id="cb12-23"><a href="#cb12-23"></a><span class="op">}</span>;</span>
<span id="cb12-24"><a href="#cb12-24"></a></span>
<span id="cb12-25"><a href="#cb12-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="cb12-26"><a href="#cb12-26"></a></span>
<span id="cb12-27"><a href="#cb12-27"></a><span class="co">/*</span></span>
<span id="cb12-28"><a href="#cb12-28"></a><span class="co">where Xd would be std::array&lt;member_descriptor, 3&gt;{{</span></span>
<span id="cb12-29"><a href="#cb12-29"></a><span class="co">  { 0, 1 }, { 4, 4 }, { 8, 8 }</span></span>
<span id="cb12-30"><a href="#cb12-30"></a><span class="co">}}</span></span>
<span id="cb12-31"><a href="#cb12-31"></a><span class="co">*/</span></span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/rbbWY99TM">On Compiler Explorer</a>.</p>
<h2 data-number="3.6" id="enum-to-string"><span class="header-section-number">3.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="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-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="cb13-2"><a href="#cb13-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="cb13-3"><a href="#cb13-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="cb13-4"><a href="#cb13-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>enumerators_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
<span id="cb13-5"><a href="#cb13-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="cb13-6"><a href="#cb13-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="cb13-7"><a href="#cb13-7"></a>    <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="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb13-11"><a href="#cb13-11"></a><span class="op">}</span></span>
<span id="cb13-12"><a href="#cb13-12"></a></span>
<span id="cb13-13"><a href="#cb13-13"></a><span class="kw">enum</span> Color <span class="op">{</span> red, green, blue <span class="op">}</span>;</span>
<span id="cb13-14"><a href="#cb13-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="cb13-15"><a href="#cb13-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="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-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="cb14-2"><a href="#cb14-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="cb14-3"><a href="#cb14-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="cb14-4"><a href="#cb14-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>enumerators_of<span class="op">(^</span>E<span class="op">))</span> <span class="op">{</span></span>
<span id="cb14-5"><a href="#cb14-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="cb14-6"><a href="#cb14-6"></a>      <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>;</span>
<span id="cb14-7"><a href="#cb14-7"></a>    <span class="op">}</span></span>
<span id="cb14-8"><a href="#cb14-8"></a>  <span class="op">}</span></span>
<span id="cb14-9"><a href="#cb14-9"></a></span>
<span id="cb14-10"><a href="#cb14-10"></a>  <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb14-11"><a href="#cb14-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), which also demonstrates choosing a different algorithm based on the number of enumerators:</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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> E<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-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="cb15-3"><a href="#cb15-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="cb15-4"><a href="#cb15-4"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> get_pairs <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb15-5"><a href="#cb15-5"></a>    <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>enumerators_of<span class="op">(^</span>E<span class="op">)</span></span>
<span id="cb15-6"><a href="#cb15-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="cb15-7"><a href="#cb15-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="cb15-8"><a href="#cb15-8"></a>        <span class="op">})</span></span>
<span id="cb15-9"><a href="#cb15-9"></a>  <span class="op">}</span>;</span>
<span id="cb15-10"><a href="#cb15-10"></a></span>
<span id="cb15-11"><a href="#cb15-11"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> get_name <span class="op">=</span> <span class="op">[](</span>E value<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>optional<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb15-12"><a href="#cb15-12"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>enumerators_of<span class="op">(^</span>E<span class="op">).</span>size<span class="op">()</span> <span class="op">&lt;=</span> <span class="dv">7</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-13"><a href="#cb15-13"></a>      <span class="co">// if there aren&#39;t many enumerators, use a vector with find_if()</span></span>
<span id="cb15-14"><a href="#cb15-14"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> enumerators <span class="op">=</span> get_pairs<span class="op">()</span> <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="cb15-15"><a href="#cb15-15"></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>enumerators, <span class="op">[</span>value<span class="op">](</span><span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> pr<span class="op">){</span></span>
<span id="cb15-16"><a href="#cb15-16"></a>        <span class="cf">return</span> pr<span class="op">.</span>first <span class="op">==</span> value;</span>
<span id="cb15-17"><a href="#cb15-17"></a>      <span class="op">}</span>;</span>
<span id="cb15-18"><a href="#cb15-18"></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="cb15-19"><a href="#cb15-19"></a>        <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb15-20"><a href="#cb15-20"></a>      <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb15-21"><a href="#cb15-21"></a>        <span class="cf">return</span> it<span class="op">-&gt;</span>second;</span>
<span id="cb15-22"><a href="#cb15-22"></a>      <span class="op">}</span></span>
<span id="cb15-23"><a href="#cb15-23"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb15-24"><a href="#cb15-24"></a>      <span class="co">// if there are lots of enumerators, use a map with find()</span></span>
<span id="cb15-25"><a href="#cb15-25"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> enumerators <span class="op">=</span> get_pairs<span class="op">()</span> <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="cb15-26"><a href="#cb15-26"></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="cb15-27"><a href="#cb15-27"></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="cb15-28"><a href="#cb15-28"></a>        <span class="cf">return</span> std<span class="op">::</span>nullopt;</span>
<span id="cb15-29"><a href="#cb15-29"></a>      <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb15-30"><a href="#cb15-30"></a>        <span class="cf">return</span> it<span class="op">-&gt;</span>second;</span>
<span id="cb15-31"><a href="#cb15-31"></a>      <span class="op">}</span></span>
<span id="cb15-32"><a href="#cb15-32"></a>    <span class="op">}</span></span>
<span id="cb15-33"><a href="#cb15-33"></a>  <span class="op">}</span>;</span>
<span id="cb15-34"><a href="#cb15-34"></a></span>
<span id="cb15-35"><a href="#cb15-35"></a>  <span class="cf">return</span> get_name<span class="op">(</span>value<span class="op">).</span>value_or<span class="op">(</span><span class="st">&quot;&lt;unnamed&gt;&quot;</span><span class="op">)</span>;</span>
<span id="cb15-36"><a href="#cb15-36"></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>
<p><a href="https://godbolt.org/z/Y5va8MqzG">On Compiler Explorer</a>.</p>
<p>Many many variations of these functions are possible and beneficial depending on the needs of the client code. For example:</p>
<ul>
<li>the <code class="sourceCode cpp"><span class="st">&quot;&lt;unnamed&gt;&quot;</span></code> case could instead output a valid cast expression like <code class="sourceCode cpp"><span class="st">&quot;E(5)&quot;</span></code></li>
<li>a compact two-way persistent data structure could be generated to support both <code class="sourceCode cpp">enum_to_string</code> and <code class="sourceCode cpp">string_to_enum</code> with a minimal footprint</li>
<li>etc.</li>
</ul>
<h2 data-number="3.7" id="parsing-command-line-options"><span class="header-section-number">3.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="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-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="cb16-2"><a href="#cb16-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="cb16-3"><a href="#cb16-3"></a>  Opts opts;</span>
<span id="cb16-4"><a href="#cb16-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="cb16-5"><a href="#cb16-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="cb16-6"><a href="#cb16-6"></a>      <span class="op">[](</span>std<span class="op">::</span>string_view arg<span class="op">){</span></span>
<span id="cb16-7"><a href="#cb16-7"></a>        <span class="cf">return</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>dm<span class="op">)</span>;</span>
<span id="cb16-8"><a href="#cb16-8"></a>      <span class="op">})</span>;</span>
<span id="cb16-9"><a href="#cb16-9"></a></span>
<span id="cb16-10"><a href="#cb16-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="cb16-11"><a href="#cb16-11"></a>      <span class="co">// no option provided, use default</span></span>
<span id="cb16-12"><a href="#cb16-12"></a>      <span class="cf">continue</span>;</span>
<span id="cb16-13"><a href="#cb16-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="cb16-14"><a href="#cb16-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="cb16-15"><a href="#cb16-15"></a>      std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb16-16"><a href="#cb16-16"></a>    <span class="op">}</span></span>
<span id="cb16-17"><a href="#cb16-17"></a></span>
<span id="cb16-18"><a href="#cb16-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="cb16-19"><a href="#cb16-19"></a>    <span class="kw">auto</span> iss <span class="op">=</span> std<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-20"><a href="#cb16-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="cb16-21"><a href="#cb16-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="cb16-22"><a href="#cb16-22"></a>      std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<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="op">}</span></span>
<span id="cb16-25"><a href="#cb16-25"></a>  <span class="cf">return</span> opts;</span>
<span id="cb16-26"><a href="#cb16-26"></a><span class="op">}</span></span>
<span id="cb16-27"><a href="#cb16-27"></a></span>
<span id="cb16-28"><a href="#cb16-28"></a><span class="kw">struct</span> MyOpts <span class="op">{</span></span>
<span id="cb16-29"><a href="#cb16-29"></a>  std<span class="op">::</span>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="cb16-30"><a href="#cb16-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="cb16-31"><a href="#cb16-31"></a><span class="op">}</span>;</span>
<span id="cb16-32"><a href="#cb16-32"></a></span>
<span id="cb16-33"><a href="#cb16-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="cb16-34"><a href="#cb16-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="cb16-35"><a href="#cb16-35"></a>  <span class="co">// ...</span></span>
<span id="cb16-36"><a href="#cb16-36"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This example is based on a presentation by Matúš Chochlík.</p>
<p><a href="https://godbolt.org/z/G4dh3jq8a">On Compiler Explorer</a>.</p>
<h2 data-number="3.8" id="a-simple-tuple-type"><span class="header-section-number">3.8</span> A Simple Tuple Type<a href="#a-simple-tuple-type" class="self-link"></a></h2>
<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="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a></span>
<span id="cb17-3"><a href="#cb17-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="cb17-4"><a href="#cb17-4"></a>  <span class="kw">struct</span> storage;</span>
<span id="cb17-5"><a href="#cb17-5"></a></span>
<span id="cb17-6"><a href="#cb17-6"></a>  <span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>define_class<span class="op">(^</span>storage, <span class="op">{</span>data_member_spec<span class="op">(^</span>Ts<span class="op">)...})))</span>;</span>
<span id="cb17-7"><a href="#cb17-7"></a>  storage data;</span>
<span id="cb17-8"><a href="#cb17-8"></a></span>
<span id="cb17-9"><a href="#cb17-9"></a>  Tuple<span class="op">():</span> data<span class="op">{}</span> <span class="op">{}</span></span>
<span id="cb17-10"><a href="#cb17-10"></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="cb17-11"><a href="#cb17-11"></a><span class="op">}</span>;</span>
<span id="cb17-12"><a href="#cb17-12"></a></span>
<span id="cb17-13"><a href="#cb17-13"></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="cb17-14"><a href="#cb17-14"></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="cb17-15"><a href="#cb17-15"></a></span>
<span id="cb17-16"><a href="#cb17-16"></a><span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span> I, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb17-17"><a href="#cb17-17"></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="cb17-18"><a href="#cb17-18"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> std<span class="op">::</span>array types <span class="op">=</span> <span class="op">{^</span>Ts<span class="op">...}</span>;</span>
<span id="cb17-19"><a href="#cb17-19"></a>    <span class="kw">using</span> type <span class="op">=</span> <span class="op">[:</span> types<span class="op">[</span>I<span class="op">]</span> <span class="op">:]</span>;</span>
<span id="cb17-20"><a href="#cb17-20"></a>  <span class="op">}</span>;</span>
<span id="cb17-21"><a href="#cb17-21"></a></span>
<span id="cb17-22"><a href="#cb17-22"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info get_nth_field<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info r, std<span class="op">::</span><span class="dt">size_t</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-23"><a href="#cb17-23"></a>  <span class="cf">return</span> nonstatic_data_members_of<span class="op">(</span>r<span class="op">)[</span>n<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="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span> I, <span class="kw">typename</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb17-27"><a href="#cb17-27"></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="cb17-28"><a href="#cb17-28"></a>    <span class="cf">return</span> t<span class="op">.</span>data<span class="op">.[:</span>get_nth_field<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="cb17-29"><a href="#cb17-29"></a>  <span class="op">}</span></span>
<span id="cb17-30"><a href="#cb17-30"></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>define_class</code> template along with member reflection through the <code class="sourceCode cpp">nonstatic_data_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. <code class="sourceCode cpp">define_class</code> takes a reflection for an incomplete class or union plus a vector of nonstatic data member descriptions, and completes the give class or union type to have the described members.</p>
<p><a href="https://godbolt.org/z/4P15rnbxh">On Compiler Explorer</a>.</p>
<h2 data-number="3.9" id="a-simple-variant-type"><span class="header-section-number">3.9</span> A Simple Variant Type<a href="#a-simple-variant-type" class="self-link"></a></h2>
<p>Similarly to how we can implement a tuple using <code class="sourceCode cpp">define_class</code> to create on the fly a type with one member for each <code class="sourceCode cpp">Ts<span class="op">...</span></code>, we can implement a variant that simply defines a <code class="sourceCode cpp"><span class="kw">union</span></code> instead of a <code class="sourceCode cpp"><span class="kw">struct</span></code>. One difference here is how the destructor of a <code class="sourceCode cpp"><span class="kw">union</span></code> is currently defined:</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">union</span> U1 <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2"></a>  <span class="dt">int</span> i;</span>
<span id="cb18-3"><a href="#cb18-3"></a>  <span class="dt">char</span> c;</span>
<span id="cb18-4"><a href="#cb18-4"></a><span class="op">}</span>;</span>
<span id="cb18-5"><a href="#cb18-5"></a></span>
<span id="cb18-6"><a href="#cb18-6"></a><span class="kw">union</span> U2 <span class="op">{</span></span>
<span id="cb18-7"><a href="#cb18-7"></a>  <span class="dt">int</span> i;</span>
<span id="cb18-8"><a href="#cb18-8"></a>  std<span class="op">::</span>string s;</span>
<span id="cb18-9"><a href="#cb18-9"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">U1</code> has a trivial destructor, but <code class="sourceCode cpp">U2</code>’s destructor is defined as deleted (because <code class="sourceCode cpp">std<span class="op">::</span>string</code> has a non-trivial destructor). This is a problem because we need to define this thing… somehow. However, for the purposes of <code class="sourceCode cpp">define_class</code>, there really is only one reasonable option to choose here:</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">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb19-2"><a href="#cb19-2"></a><span class="kw">union</span> U <span class="op">{</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>  <span class="co">// all of our members</span></span>
<span id="cb19-4"><a href="#cb19-4"></a>  Ts<span class="op">...</span> members;</span>
<span id="cb19-5"><a href="#cb19-5"></a></span>
<span id="cb19-6"><a href="#cb19-6"></a>  <span class="co">// a defaulted destructor if all of the types are trivially destructible</span></span>
<span id="cb19-7"><a href="#cb19-7"></a>  <span class="kw">constexpr</span> <span class="op">~</span>U<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>is_trivially_destructible_v<span class="op">&lt;</span>Ts<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb19-8"><a href="#cb19-8"></a></span>
<span id="cb19-9"><a href="#cb19-9"></a>  <span class="co">// ... otherwise a destructor that does nothing</span></span>
<span id="cb19-10"><a href="#cb19-10"></a>  <span class="kw">constexpr</span> <span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb19-11"><a href="#cb19-11"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>If we make <a href="#data_member_spec-define_class"><code class="sourceCode cpp">define_class</code></a> for a <code class="sourceCode cpp"><span class="kw">union</span></code> have this behavior, then we can implement a <code class="sourceCode cpp">variant</code> in a much more straightforward way than in current implementations. This is not a complete implementation of <code class="sourceCode cpp">std<span class="op">::</span>variant</code> (and cheats using libstdc++ internals, and also uses Boost.Mp11’s <code class="sourceCode cpp">mp_with_index</code>) but should demonstrate the idea:</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">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="cb20-2"><a href="#cb20-2"></a><span class="kw">class</span> Variant <span class="op">{</span></span>
<span id="cb20-3"><a href="#cb20-3"></a>    <span class="kw">union</span> Storage;</span>
<span id="cb20-4"><a href="#cb20-4"></a>    <span class="kw">struct</span> Empty <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb20-5"><a href="#cb20-5"></a></span>
<span id="cb20-6"><a href="#cb20-6"></a>    <span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>define_class<span class="op">(^</span>Storage, <span class="op">{</span></span>
<span id="cb20-7"><a href="#cb20-7"></a>        data_member_spec<span class="op">(^</span>Empty, <span class="op">{.</span>name<span class="op">=</span><span class="st">&quot;empty&quot;</span><span class="op">})</span>,</span>
<span id="cb20-8"><a href="#cb20-8"></a>        data_member_spec<span class="op">(^</span>Ts<span class="op">)...</span></span>
<span id="cb20-9"><a href="#cb20-9"></a>    <span class="op">})))</span>;</span>
<span id="cb20-10"><a href="#cb20-10"></a></span>
<span id="cb20-11"><a href="#cb20-11"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> std<span class="op">::</span>array<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info, <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;</span> types <span class="op">=</span> <span class="op">{^</span>Ts<span class="op">...}</span>;</span>
<span id="cb20-12"><a href="#cb20-12"></a></span>
<span id="cb20-13"><a href="#cb20-13"></a>    <span class="kw">static</span> <span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info get_nth_field<span class="op">(</span>std<span class="op">::</span><span class="dt">size_t</span> n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-14"><a href="#cb20-14"></a>        <span class="cf">return</span> nonstatic_data_members_of<span class="op">(^</span>Storage<span class="op">)[</span>n<span class="op">+</span><span class="dv">1</span><span class="op">]</span>;</span>
<span id="cb20-15"><a href="#cb20-15"></a>    <span class="op">}</span></span>
<span id="cb20-16"><a href="#cb20-16"></a></span>
<span id="cb20-17"><a href="#cb20-17"></a>    Storage storage_;</span>
<span id="cb20-18"><a href="#cb20-18"></a>    <span class="dt">int</span> index_ <span class="op">=</span> <span class="op">-</span><span class="dv">1</span>;</span>
<span id="cb20-19"><a href="#cb20-19"></a></span>
<span id="cb20-20"><a href="#cb20-20"></a>    <span class="co">// cheat: use libstdc++&#39;s implementation</span></span>
<span id="cb20-21"><a href="#cb20-21"></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="cb20-22"><a href="#cb20-22"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> accepted_index <span class="op">=</span> std<span class="op">::</span>__detail<span class="op">::</span>__variant<span class="op">::</span>__accepted_index<span class="op">&lt;</span>T, std<span class="op">::</span>variant<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span>;</span>
<span id="cb20-23"><a href="#cb20-23"></a></span>
<span id="cb20-24"><a href="#cb20-24"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F<span class="op">&gt;</span></span>
<span id="cb20-25"><a href="#cb20-25"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> with_index<span class="op">(</span>F<span class="op">&amp;&amp;</span> f<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-26"><a href="#cb20-26"></a>        <span class="cf">return</span> mp_with_index<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;(</span>index_, <span class="op">(</span>F<span class="op">&amp;&amp;)</span>f<span class="op">)</span>;</span>
<span id="cb20-27"><a href="#cb20-27"></a>    <span class="op">}</span></span>
<span id="cb20-28"><a href="#cb20-28"></a></span>
<span id="cb20-29"><a href="#cb20-29"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb20-30"><a href="#cb20-30"></a>    <span class="kw">constexpr</span> Variant<span class="op">()</span> <span class="kw">requires</span> std<span class="op">::</span>is_default_constructible_v<span class="op">&lt;[:</span> types<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">:]&gt;</span></span>
<span id="cb20-31"><a href="#cb20-31"></a>        <span class="co">// should this work: storage_{. [: get_nth_field(0) :]{} }</span></span>
<span id="cb20-32"><a href="#cb20-32"></a>        <span class="op">:</span> storage_<span class="op">{.</span>empty<span class="op">={}}</span></span>
<span id="cb20-33"><a href="#cb20-33"></a>        , index_<span class="op">(</span><span class="dv">0</span><span class="op">)</span></span>
<span id="cb20-34"><a href="#cb20-34"></a>    <span class="op">{</span></span>
<span id="cb20-35"><a href="#cb20-35"></a>        std<span class="op">::</span>construct_at<span class="op">(&amp;</span>storage_<span class="op">.[:</span> get_nth_field<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">:])</span>;</span>
<span id="cb20-36"><a href="#cb20-36"></a>    <span class="op">}</span></span>
<span id="cb20-37"><a href="#cb20-37"></a></span>
<span id="cb20-38"><a href="#cb20-38"></a>    <span class="kw">constexpr</span> <span class="op">~</span>Variant<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>is_trivially_destructible_v<span class="op">&lt;</span>Ts<span class="op">&gt;</span> <span class="kw">and</span> <span class="op">...)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb20-39"><a href="#cb20-39"></a>    <span class="kw">constexpr</span> <span class="op">~</span>Variant<span class="op">()</span> <span class="op">{</span></span>
<span id="cb20-40"><a href="#cb20-40"></a>        <span class="cf">if</span> <span class="op">(</span>index_ <span class="op">!=</span> <span class="op">-</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-41"><a href="#cb20-41"></a>            with_index<span class="op">([&amp;](</span><span class="kw">auto</span> I<span class="op">){</span></span>
<span id="cb20-42"><a href="#cb20-42"></a>                std<span class="op">::</span>destroy_at<span class="op">(&amp;</span>storage_<span class="op">.[:</span> get_nth_field<span class="op">(</span>I<span class="op">)</span> <span class="op">:])</span>;</span>
<span id="cb20-43"><a href="#cb20-43"></a>            <span class="op">})</span>;</span>
<span id="cb20-44"><a href="#cb20-44"></a>        <span class="op">}</span></span>
<span id="cb20-45"><a href="#cb20-45"></a>    <span class="op">}</span></span>
<span id="cb20-46"><a href="#cb20-46"></a></span>
<span id="cb20-47"><a href="#cb20-47"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> I <span class="op">=</span> accepted_index<span class="op">&lt;</span>T<span class="op">&amp;&amp;&gt;&gt;</span></span>
<span id="cb20-48"><a href="#cb20-48"></a>        <span class="kw">requires</span> <span class="op">(!</span>std<span class="op">::</span>is_base_of_v<span class="op">&lt;</span>Variant, std<span class="op">::</span>decay_t<span class="op">&lt;</span>T<span class="op">&gt;&gt;)</span></span>
<span id="cb20-49"><a href="#cb20-49"></a>    <span class="kw">constexpr</span> Variant<span class="op">(</span>T<span class="op">&amp;&amp;</span> t<span class="op">)</span></span>
<span id="cb20-50"><a href="#cb20-50"></a>        <span class="op">:</span> storage_<span class="op">{.</span>empty<span class="op">={}}</span></span>
<span id="cb20-51"><a href="#cb20-51"></a>        , index_<span class="op">(-</span><span class="dv">1</span><span class="op">)</span></span>
<span id="cb20-52"><a href="#cb20-52"></a>    <span class="op">{</span></span>
<span id="cb20-53"><a href="#cb20-53"></a>        std<span class="op">::</span>construct_at<span class="op">(&amp;</span>storage_<span class="op">.[:</span> get_nth_field<span class="op">(</span>I<span class="op">)</span> <span class="op">:]</span>, <span class="op">(</span>T<span class="op">&amp;&amp;)</span>t<span class="op">)</span>;</span>
<span id="cb20-54"><a href="#cb20-54"></a>        index_ <span class="op">=</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span>I;</span>
<span id="cb20-55"><a href="#cb20-55"></a>    <span class="op">}</span></span>
<span id="cb20-56"><a href="#cb20-56"></a></span>
<span id="cb20-57"><a href="#cb20-57"></a>    <span class="co">// you can&#39;t actually express this constraint nicely until P2963</span></span>
<span id="cb20-58"><a href="#cb20-58"></a>    <span class="kw">constexpr</span> Variant<span class="op">(</span>Variant <span class="kw">const</span><span class="op">&amp;)</span> <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>is_trivially_copyable_v<span class="op">&lt;</span>Ts<span class="op">&gt;</span> <span class="kw">and</span> <span class="op">...)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb20-59"><a href="#cb20-59"></a>    <span class="kw">constexpr</span> Variant<span class="op">(</span>Variant <span class="kw">const</span><span class="op">&amp;</span> rhs<span class="op">)</span></span>
<span id="cb20-60"><a href="#cb20-60"></a>            <span class="kw">requires</span> <span class="op">((</span>std<span class="op">::</span>is_copy_constructible_v<span class="op">&lt;</span>Ts<span class="op">&gt;</span> <span class="kw">and</span> <span class="op">...)</span></span>
<span id="cb20-61"><a href="#cb20-61"></a>                <span class="kw">and</span> <span class="kw">not</span> <span class="op">(</span>std<span class="op">::</span>is_trivially_copyable_v<span class="op">&lt;</span>Ts<span class="op">&gt;</span> <span class="kw">and</span> <span class="op">...))</span></span>
<span id="cb20-62"><a href="#cb20-62"></a>        <span class="op">:</span> storage_<span class="op">{.</span>empty<span class="op">={}}</span></span>
<span id="cb20-63"><a href="#cb20-63"></a>        , index_<span class="op">(-</span><span class="dv">1</span><span class="op">)</span></span>
<span id="cb20-64"><a href="#cb20-64"></a>    <span class="op">{</span></span>
<span id="cb20-65"><a href="#cb20-65"></a>        rhs<span class="op">.</span>with_index<span class="op">([&amp;](</span><span class="kw">auto</span> I<span class="op">){</span></span>
<span id="cb20-66"><a href="#cb20-66"></a>            <span class="kw">constexpr</span> <span class="kw">auto</span> field <span class="op">=</span> get_nth_field<span class="op">(</span>I<span class="op">)</span>;</span>
<span id="cb20-67"><a href="#cb20-67"></a>            std<span class="op">::</span>construct_at<span class="op">(&amp;</span>storage_<span class="op">.[:</span> field <span class="op">:]</span>, rhs<span class="op">.</span>storage_<span class="op">.[:</span> field <span class="op">:])</span>;</span>
<span id="cb20-68"><a href="#cb20-68"></a>            index_ <span class="op">=</span> I;</span>
<span id="cb20-69"><a href="#cb20-69"></a>        <span class="op">})</span>;</span>
<span id="cb20-70"><a href="#cb20-70"></a>    <span class="op">}</span></span>
<span id="cb20-71"><a href="#cb20-71"></a></span>
<span id="cb20-72"><a href="#cb20-72"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> index<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{</span> <span class="cf">return</span> index_; <span class="op">}</span></span>
<span id="cb20-73"><a href="#cb20-73"></a></span>
<span id="cb20-74"><a href="#cb20-74"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F<span class="op">&gt;</span></span>
<span id="cb20-75"><a href="#cb20-75"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> visit<span class="op">(</span>F<span class="op">&amp;&amp;</span> f<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-76"><a href="#cb20-76"></a>        <span class="cf">if</span> <span class="op">(</span>index_ <span class="op">==</span> <span class="op">-</span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-77"><a href="#cb20-77"></a>            <span class="cf">throw</span> std<span class="op">::</span>bad_variant_access<span class="op">()</span>;</span>
<span id="cb20-78"><a href="#cb20-78"></a>        <span class="op">}</span></span>
<span id="cb20-79"><a href="#cb20-79"></a></span>
<span id="cb20-80"><a href="#cb20-80"></a>        <span class="cf">return</span> mp_with_index<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">)&gt;(</span>index_, <span class="op">[&amp;](</span><span class="kw">auto</span> I<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-81"><a href="#cb20-81"></a>            <span class="cf">return</span> std<span class="op">::</span>invoke<span class="op">((</span>F<span class="op">&amp;&amp;)</span>f,  storage_<span class="op">.[:</span> get_nth_field<span class="op">(</span>I<span class="op">)</span> <span class="op">:])</span>;</span>
<span id="cb20-82"><a href="#cb20-82"></a>        <span class="op">})</span>;</span>
<span id="cb20-83"><a href="#cb20-83"></a>    <span class="op">}</span></span>
<span id="cb20-84"><a href="#cb20-84"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>Effectively, <code class="sourceCode cpp">Variant<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> synthesizes a union type <code class="sourceCode cpp">Storage</code> which looks like this:</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">union</span> Storage <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2"></a>    Empty empty;</span>
<span id="cb21-3"><a href="#cb21-3"></a>    T <em>unnamed<sub>0</sub></em>;</span>
<span id="cb21-4"><a href="#cb21-4"></a>    U <em>unnamed<sub>1</sub></em>;</span>
<span id="cb21-5"><a href="#cb21-5"></a></span>
<span id="cb21-6"><a href="#cb21-6"></a>    <span class="op">~</span>Storage<span class="op">()</span> <span class="kw">requires</span> std<span class="op">::</span>is_trivially_destructible_v<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> std<span class="op">::</span>is_trivially_destructible_v<span class="op">&lt;</span>U<span class="op">&gt;</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb21-7"><a href="#cb21-7"></a>    <span class="op">~</span>Storage<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb21-8"><a href="#cb21-8"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>The question here is whether we should be should be able to directly initialize members of a defined union using a splicer, as in:</p>
<blockquote>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a><span class="op">:</span> storage<span class="op">{.[:</span> get_nth_field<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">:]={}}</span></span></code></pre></div>
</blockquote>
<p>Arguably, the answer should be yes - this would be consistent with how other accesses work.</p>
<p><a href="https://godbolt.org/z/Efz5vsjaa">On Compiler Explorer</a>.</p>
<h2 data-number="3.10" id="struct-to-struct-of-arrays"><span class="header-section-number">3.10</span> Struct to Struct of Arrays<a href="#struct-to-struct-of-arrays" class="self-link"></a></h2>
<blockquote>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2"></a><span class="pp">#include </span><span class="im">&lt;array&gt;</span></span>
<span id="cb23-3"><a href="#cb23-3"></a></span>
<span id="cb23-4"><a href="#cb23-4"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, std<span class="op">::</span><span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb23-5"><a href="#cb23-5"></a><span class="kw">struct</span> struct_of_arrays_impl;</span>
<span id="cb23-6"><a href="#cb23-6"></a></span>
<span id="cb23-7"><a href="#cb23-7"></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>
<span id="cb23-8"><a href="#cb23-8"></a>                                     std<span class="op">::</span>meta<span class="op">::</span>info 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="cb23-9"><a href="#cb23-9"></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> old_members <span class="op">=</span> nonstatic_data_members_of<span class="op">(</span>type<span class="op">)</span>;</span>
<span id="cb23-10"><a href="#cb23-10"></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 class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb23-11"><a href="#cb23-11"></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> old_members<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-12"><a href="#cb23-12"></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>, N <span class="op">})</span>;</span>
<span id="cb23-13"><a href="#cb23-13"></a>    <span class="kw">auto</span> mem_descr <span class="op">=</span> data_member_spec<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="cb23-14"><a href="#cb23-14"></a>    new_members<span class="op">.</span>push_back<span class="op">(</span>mem_descr<span class="op">)</span>;</span>
<span id="cb23-15"><a href="#cb23-15"></a>  <span class="op">}</span></span>
<span id="cb23-16"><a href="#cb23-16"></a>  <span class="cf">return</span> std<span class="op">::</span>meta<span class="op">::</span>define_class<span class="op">(</span></span>
<span id="cb23-17"><a href="#cb23-17"></a>    substitute<span class="op">(^</span>struct_of_arrays_impl, <span class="op">{</span>type, N<span class="op">})</span>,</span>
<span id="cb23-18"><a href="#cb23-18"></a>    new_members<span class="op">)</span>;</span>
<span id="cb23-19"><a href="#cb23-19"></a><span class="op">}</span></span>
<span id="cb23-20"><a href="#cb23-20"></a></span>
<span id="cb23-21"><a href="#cb23-21"></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="cb23-22"><a href="#cb23-22"></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, <span class="op">^</span>N<span class="op">)</span> <span class="op">:]</span>;</span></code></pre></div>
</blockquote>
<p>Example:</p>
<blockquote>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></a><span class="kw">struct</span> point <span class="op">{</span></span>
<span id="cb24-2"><a href="#cb24-2"></a>  <span class="dt">float</span> x;</span>
<span id="cb24-3"><a href="#cb24-3"></a>  <span class="dt">float</span> y;</span>
<span id="cb24-4"><a href="#cb24-4"></a>  <span class="dt">float</span> z;</span>
<span id="cb24-5"><a href="#cb24-5"></a><span class="op">}</span>;</span>
<span id="cb24-6"><a href="#cb24-6"></a></span>
<span id="cb24-7"><a href="#cb24-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="cb24-8"><a href="#cb24-8"></a><span class="co">// equivalent to:</span></span>
<span id="cb24-9"><a href="#cb24-9"></a><span class="co">// struct points {</span></span>
<span id="cb24-10"><a href="#cb24-10"></a><span class="co">//   std::array&lt;float, 30&gt; x;</span></span>
<span id="cb24-11"><a href="#cb24-11"></a><span class="co">//   std::array&lt;float, 30&gt; y;</span></span>
<span id="cb24-12"><a href="#cb24-12"></a><span class="co">//   std::array&lt;float, 30&gt; z;</span></span>
<span id="cb24-13"><a href="#cb24-13"></a><span class="co">// };</span></span></code></pre></div>
</blockquote>
<p>Again, the combination of <code class="sourceCode cpp">nonstatic_data_members_of</code> and <code class="sourceCode cpp">define_class</code> is put to good use.</p>
<p><a href="https://godbolt.org/z/8rT77KxjP">On Compiler Explorer</a>.</p>
<h2 data-number="3.11" id="parsing-command-line-options-ii"><span class="header-section-number">3.11</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>define_class</code> to create a type, we can create a more sophisticated command-line parser example.</p>
<p>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="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a><span class="kw">struct</span> Args <span class="op">:</span> Clap <span class="op">{</span></span>
<span id="cb25-2"><a href="#cb25-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="cb25-3"><a href="#cb25-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="cb25-4"><a href="#cb25-4"></a><span class="op">}</span>;</span>
<span id="cb25-5"><a href="#cb25-5"></a></span>
<span id="cb25-6"><a href="#cb25-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="cb25-7"><a href="#cb25-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="cb25-8"><a href="#cb25-8"></a></span>
<span id="cb25-9"><a href="#cb25-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="cb25-10"><a href="#cb25-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="cb25-11"><a href="#cb25-11"></a>  <span class="op">}</span></span>
<span id="cb25-12"><a href="#cb25-12"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Which we can implement like this:</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">struct</span> Flags <span class="op">{</span></span>
<span id="cb26-2"><a href="#cb26-2"></a>  <span class="dt">bool</span> use_short;</span>
<span id="cb26-3"><a href="#cb26-3"></a>  <span class="dt">bool</span> use_long;</span>
<span id="cb26-4"><a href="#cb26-4"></a><span class="op">}</span>;</span>
<span id="cb26-5"><a href="#cb26-5"></a></span>
<span id="cb26-6"><a href="#cb26-6"></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="cb26-7"><a href="#cb26-7"></a><span class="kw">struct</span> Option <span class="op">{</span></span>
<span id="cb26-8"><a href="#cb26-8"></a>  std<span class="op">::</span>optional<span class="op">&lt;</span>T<span class="op">&gt;</span> initializer <span class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb26-9"><a href="#cb26-9"></a></span>
<span id="cb26-10"><a href="#cb26-10"></a>  <span class="co">// some suitable constructors and accessors for flags</span></span>
<span id="cb26-11"><a href="#cb26-11"></a><span class="op">}</span>;</span>
<span id="cb26-12"><a href="#cb26-12"></a></span>
<span id="cb26-13"><a href="#cb26-13"></a><span class="co">// convert a type (all of whose non-static data members are specializations of Option)</span></span>
<span id="cb26-14"><a href="#cb26-14"></a><span class="co">// to a type that is just the appropriate members.</span></span>
<span id="cb26-15"><a href="#cb26-15"></a><span class="co">// For example, if type is a reflection of the Args presented above, then this</span></span>
<span id="cb26-16"><a href="#cb26-16"></a><span class="co">// function would evaluate to a reflection of the type</span></span>
<span id="cb26-17"><a href="#cb26-17"></a><span class="co">// struct {</span></span>
<span id="cb26-18"><a href="#cb26-18"></a><span class="co">//   std::string name;</span></span>
<span id="cb26-19"><a href="#cb26-19"></a><span class="co">//   int count;</span></span>
<span id="cb26-20"><a href="#cb26-20"></a><span class="co">// }</span></span>
<span id="cb26-21"><a href="#cb26-21"></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 opts,</span>
<span id="cb26-22"><a href="#cb26-22"></a>                            std<span class="op">::</span>meta<span class="op">::</span>info spec<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="cb26-23"><a href="#cb26-23"></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="cb26-24"><a href="#cb26-24"></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>spec<span class="op">))</span> <span class="op">{</span></span>
<span id="cb26-25"><a href="#cb26-25"></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="cb26-26"><a href="#cb26-26"></a>    new_members<span class="op">.</span>push_back<span class="op">(</span>data_member_spec<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="cb26-27"><a href="#cb26-27"></a>  <span class="op">}</span></span>
<span id="cb26-28"><a href="#cb26-28"></a>  <span class="cf">return</span> define_class<span class="op">(</span>opts, new_members<span class="op">)</span>;</span>
<span id="cb26-29"><a href="#cb26-29"></a><span class="op">}</span></span>
<span id="cb26-30"><a href="#cb26-30"></a></span>
<span id="cb26-31"><a href="#cb26-31"></a><span class="kw">struct</span> Clap <span class="op">{</span></span>
<span id="cb26-32"><a href="#cb26-32"></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="cb26-33"><a href="#cb26-33"></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="cb26-34"><a href="#cb26-34"></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="cb26-35"><a href="#cb26-35"></a></span>
<span id="cb26-36"><a href="#cb26-36"></a>    <span class="co">// check if cmdline contains --help, etc.</span></span>
<span id="cb26-37"><a href="#cb26-37"></a></span>
<span id="cb26-38"><a href="#cb26-38"></a>    <span class="kw">struct</span> Opts;</span>
<span id="cb26-39"><a href="#cb26-39"></a>    <span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>spec_to_opts<span class="op">(^</span>Opts, <span class="op">^</span>Spec<span class="op">)))</span>;</span>
<span id="cb26-40"><a href="#cb26-40"></a>    Opts opts;</span>
<span id="cb26-41"><a href="#cb26-41"></a></span>
<span id="cb26-42"><a href="#cb26-42"></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="cb26-43"><a href="#cb26-43"></a>                                                            nonstatic_data_members_of<span class="op">(^</span>Opts<span class="op">)))</span> <span class="op">{</span></span>
<span id="cb26-44"><a href="#cb26-44"></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="cb26-45"><a href="#cb26-45"></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="cb26-46"><a href="#cb26-46"></a></span>
<span id="cb26-47"><a href="#cb26-47"></a>      <span class="co">// find the argument associated with this option</span></span>
<span id="cb26-48"><a href="#cb26-48"></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="cb26-49"><a href="#cb26-49"></a>        <span class="op">[&amp;](</span>std<span class="op">::</span>string_view arg<span class="op">){</span></span>
<span id="cb26-50"><a href="#cb26-50"></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>size<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span> <span class="op">&amp;&amp;</span> arg<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;-&#39;</span> <span class="op">&amp;&amp;</span> arg<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 class="dv">0</span><span class="op">])</span></span>
<span id="cb26-51"><a href="#cb26-51"></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="cb26-52"><a href="#cb26-52"></a>        <span class="op">})</span>;</span>
<span id="cb26-53"><a href="#cb26-53"></a></span>
<span id="cb26-54"><a href="#cb26-54"></a>      <span class="co">// no such argument</span></span>
<span id="cb26-55"><a href="#cb26-55"></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="cb26-56"><a href="#cb26-56"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>has_template_arguments<span class="op">(</span>type<span class="op">)</span> <span class="kw">and</span> template_of<span class="op">(</span>type<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="cb26-57"><a href="#cb26-57"></a>          <span class="co">// the type is optional, so the argument is too</span></span>
<span id="cb26-58"><a href="#cb26-58"></a>          <span class="cf">continue</span>;</span>
<span id="cb26-59"><a href="#cb26-59"></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="cb26-60"><a href="#cb26-60"></a>          <span class="co">// the type isn&#39;t optional, but an initializer is provided, use that</span></span>
<span id="cb26-61"><a href="#cb26-61"></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="cb26-62"><a href="#cb26-62"></a>          <span class="cf">continue</span>;</span>
<span id="cb26-63"><a href="#cb26-63"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb26-64"><a href="#cb26-64"></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="cb26-65"><a href="#cb26-65"></a>          std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb26-66"><a href="#cb26-66"></a>        <span class="op">}</span></span>
<span id="cb26-67"><a href="#cb26-67"></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="cb26-68"><a href="#cb26-68"></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="cb26-69"><a href="#cb26-69"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb26-70"><a href="#cb26-70"></a>      <span class="op">}</span></span>
<span id="cb26-71"><a href="#cb26-71"></a></span>
<span id="cb26-72"><a href="#cb26-72"></a>      <span class="co">// found our argument, try to parse it</span></span>
<span id="cb26-73"><a href="#cb26-73"></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="cb26-74"><a href="#cb26-74"></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="cb26-75"><a href="#cb26-75"></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="cb26-76"><a href="#cb26-76"></a>          it<span class="op">[</span><span class="dv">1</span><span class="op">]</span>, 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="cb26-77"><a href="#cb26-77"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb26-78"><a href="#cb26-78"></a>      <span class="op">}</span></span>
<span id="cb26-79"><a href="#cb26-79"></a>    <span class="op">}</span></span>
<span id="cb26-80"><a href="#cb26-80"></a>    <span class="cf">return</span> opts;</span>
<span id="cb26-81"><a href="#cb26-81"></a>  <span class="op">}</span></span>
<span id="cb26-82"><a href="#cb26-82"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/1esbcq4jq">On Compiler Explorer</a>.</p>
<h2 data-number="3.12" id="a-universal-formatter"><span class="header-section-number">3.12</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="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a><span class="kw">struct</span> universal_formatter <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-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="cb27-3"><a href="#cb27-3"></a></span>
<span id="cb27-4"><a href="#cb27-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="cb27-5"><a href="#cb27-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="cb27-6"><a href="#cb27-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="cb27-7"><a href="#cb27-7"></a></span>
<span id="cb27-8"><a href="#cb27-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="cb27-9"><a href="#cb27-9"></a>      <span class="cf">if</span> <span class="op">(!</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb27-10"><a href="#cb27-10"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb27-11"><a href="#cb27-11"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb27-12"><a href="#cb27-12"></a>      <span class="op">}</span></span>
<span id="cb27-13"><a href="#cb27-13"></a>      first <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb27-14"><a href="#cb27-14"></a>    <span class="op">}</span>;</span>
<span id="cb27-15"><a href="#cb27-15"></a></span>
<span id="cb27-16"><a href="#cb27-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="cb27-17"><a href="#cb27-17"></a>      delim<span class="op">()</span>;</span>
<span id="cb27-18"><a href="#cb27-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="cb27-19"><a href="#cb27-19"></a>    <span class="op">}</span></span>
<span id="cb27-20"><a href="#cb27-20"></a></span>
<span id="cb27-21"><a href="#cb27-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="cb27-22"><a href="#cb27-22"></a>      delim<span class="op">()</span>;</span>
<span id="cb27-23"><a href="#cb27-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="cb27-24"><a href="#cb27-24"></a>    <span class="op">}</span></span>
<span id="cb27-25"><a href="#cb27-25"></a></span>
<span id="cb27-26"><a href="#cb27-26"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;}&#39;</span>;</span>
<span id="cb27-27"><a href="#cb27-27"></a>    <span class="cf">return</span> out;</span>
<span id="cb27-28"><a href="#cb27-28"></a>  <span class="op">}</span></span>
<span id="cb27-29"><a href="#cb27-29"></a><span class="op">}</span>;</span>
<span id="cb27-30"><a href="#cb27-30"></a></span>
<span id="cb27-31"><a href="#cb27-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="cb27-32"><a href="#cb27-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="cb27-33"><a href="#cb27-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="cb27-34"><a href="#cb27-34"></a></span>
<span id="cb27-35"><a href="#cb27-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="cb27-36"><a href="#cb27-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="cb27-37"><a href="#cb27-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="cb27-38"><a href="#cb27-38"></a></span>
<span id="cb27-39"><a href="#cb27-39"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-40"><a href="#cb27-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="cb27-41"><a href="#cb27-41"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This example is not implemented on compiler explorer at this time, but only because of issues compiling both <code class="sourceCode cpp">std<span class="op">::</span>format</code> and <code class="sourceCode cpp">fmt<span class="op">::</span>format<span class="op">.</span></code></p>
<h2 data-number="3.13" id="implementing-member-wise-hash_append"><span class="header-section-number">3.13</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="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-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="cb28-2"><a href="#cb28-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="cb28-3"><a href="#cb28-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="cb28-4"><a href="#cb28-4"></a>        hash_append<span class="op">(</span>algo, t<span class="op">.[:</span>mem<span class="op">:])</span>;</span>
<span id="cb28-5"><a href="#cb28-5"></a>    <span class="op">}</span></span>
<span id="cb28-6"><a href="#cb28-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="3.14" id="converting-a-struct-to-a-tuple"><span class="header-section-number">3.14</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="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">typename</span> T<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-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="cb29-3"><a href="#cb29-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="cb29-4"><a href="#cb29-4"></a></span>
<span id="cb29-5"><a href="#cb29-5"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> indices <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb29-6"><a href="#cb29-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="cb29-7"><a href="#cb29-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="cb29-8"><a href="#cb29-8"></a>    <span class="cf">return</span> indices;</span>
<span id="cb29-9"><a href="#cb29-9"></a>  <span class="op">}()</span>;</span>
<span id="cb29-10"><a href="#cb29-10"></a></span>
<span id="cb29-11"><a href="#cb29-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="cb29-12"><a href="#cb29-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="cb29-13"><a href="#cb29-13"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>An alternative approach is:</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="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="cb30-2"><a href="#cb30-2"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>std<span class="op">::</span>tuple,</span>
<span id="cb30-3"><a href="#cb30-3"></a>                    nonstatic_data_members_of<span class="op">(</span>type<span class="op">)</span></span>
<span id="cb30-4"><a href="#cb30-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="cb30-5"><a href="#cb30-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="cb30-6"><a href="#cb30-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="cb30-7"><a href="#cb30-7"></a><span class="op">}</span></span>
<span id="cb30-8"><a href="#cb30-8"></a></span>
<span id="cb30-9"><a href="#cb30-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="cb30-10"><a href="#cb30-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="cb30-11"><a href="#cb30-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="cb30-12"><a href="#cb30-12"></a><span class="op">}</span></span>
<span id="cb30-13"><a href="#cb30-13"></a></span>
<span id="cb30-14"><a href="#cb30-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="cb30-15"><a href="#cb30-15"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_struct_to_tuple_helper<span class="op">()</span> <span class="op">{</span></span>
<span id="cb30-16"><a href="#cb30-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="cb30-17"><a href="#cb30-17"></a></span>
<span id="cb30-18"><a href="#cb30-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="cb30-19"><a href="#cb30-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="cb30-20"><a href="#cb30-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="cb30-21"><a href="#cb30-21"></a>  <span class="op">}</span></span>
<span id="cb30-22"><a href="#cb30-22"></a></span>
<span id="cb30-23"><a href="#cb30-23"></a>  <span class="co">/*</span></span>
<span id="cb30-24"><a href="#cb30-24"></a><span class="co">  Alternatively, with Ranges:</span></span>
<span id="cb30-25"><a href="#cb30-25"></a><span class="co">  args.append_range(</span></span>
<span id="cb30-26"><a href="#cb30-26"></a><span class="co">    nonstatic_data_members_of(^From)</span></span>
<span id="cb30-27"><a href="#cb30-27"></a><span class="co">    | std::views::transform(std::meta::reflect_value)</span></span>
<span id="cb30-28"><a href="#cb30-28"></a><span class="co">    );</span></span>
<span id="cb30-29"><a href="#cb30-29"></a><span class="co">  */</span></span>
<span id="cb30-30"><a href="#cb30-30"></a></span>
<span id="cb30-31"><a href="#cb30-31"></a>  <span class="cf">return</span> value_of<span class="op">&lt;</span>To<span class="op">(*)(</span>From <span class="kw">const</span><span class="op">&amp;)&gt;(</span></span>
<span id="cb30-32"><a href="#cb30-32"></a>    substitute<span class="op">(^</span>struct_to_tuple_helper, args<span class="op">))</span>;</span>
<span id="cb30-33"><a href="#cb30-33"></a><span class="op">}</span></span>
<span id="cb30-34"><a href="#cb30-34"></a></span>
<span id="cb30-35"><a href="#cb30-35"></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="cb30-36"><a href="#cb30-36"></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="cb30-37"><a href="#cb30-37"></a>  <span class="cf">return</span> get_struct_to_tuple_helper<span class="op">&lt;</span>From<span class="op">&gt;()(</span>from<span class="op">)</span>;</span>
<span id="cb30-38"><a href="#cb30-38"></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>. 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. This is a <code class="sourceCode cpp"><span class="kw">constexpr</span></code> function and not a <code class="sourceCode cpp"><span class="kw">consteval</span></code> function because in the general case the conversion is a run-time operation. However, determining the instance of <code class="sourceCode cpp">struct_to_tuple_helper</code> that is needed is a compile-time operation and has to be performed with a <code class="sourceCode cpp"><span class="kw">consteval</span></code> function (because the function invokes <code class="sourceCode cpp">nonstatic_data_members_of</code>), hence the separate function template <code class="sourceCode cpp">get_struct_to_tuple_helper<span class="op">()</span></code>.</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, and a compile-time reference to that instance is obtained with <code class="sourceCode cpp">value_of</code>. Thus <code class="sourceCode cpp">f</code> is a function reference to the correct specialization of <code class="sourceCode cpp">struct_to_tuple_helper</code>, which we can simply invoke.</p>
<p><a href="https://godbolt.org/z/Moqf84nc1">On Compiler Explorer</a>, with a different implementation than either of the above.</p>
<h2 data-number="3.15" id="named-tuple"><span class="header-section-number">3.15</span> Named Tuple<a href="#named-tuple" class="self-link"></a></h2>
<p>The tricky thing with implementing a named tuple is actually strings as non-type template parameters. Because you cannot just pass <code class="sourceCode cpp"><span class="st">&quot;x&quot;</span></code> into a non-type template parameter of the form <code class="sourceCode cpp"><span class="kw">auto</span> V</code>, that leaves us with two ways of specifying the constituents:</p>
<ol type="1">
<li>Can introduce a <code class="sourceCode cpp">pair</code> type so that we can write <code class="sourceCode cpp">make_named_tuple<span class="op">&lt;</span>pair<span class="op">&lt;</span><span class="dt">int</span>, <span class="st">&quot;x&quot;</span><span class="op">&gt;</span>, pair<span class="op">&lt;</span><span class="dt">double</span>, <span class="st">&quot;y&quot;</span><span class="op">&gt;&gt;()</span></code>, or</li>
<li>Can just do reflections all the way down so that we can write <code class="sourceCode cpp">make_named_tuple<span class="op">&lt;^</span><span class="dt">int</span>, <span class="op">^</span><span class="st">&quot;x&quot;</span>, <span class="op">^</span><span class="dt">double</span>, <span class="op">^</span><span class="st">&quot;y&quot;</span><span class="op">&gt;()</span></code>.</li>
</ol>
<p>We do not currently support splicing string literals (although that may change in the next revision), and the <code class="sourceCode cpp">pair</code> approach follows the similar pattern already shown with <code class="sourceCode cpp">define_class</code> (given a suitable <code class="sourceCode cpp">fixed_string</code> type):</p>
<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">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, fixed_string Name<span class="op">&gt;</span></span>
<span id="cb31-2"><a href="#cb31-2"></a><span class="kw">struct</span> pair <span class="op">{</span></span>
<span id="cb31-3"><a href="#cb31-3"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> name<span class="op">()</span> <span class="op">-&gt;</span> std<span class="op">::</span>string_view <span class="op">{</span> <span class="cf">return</span> Name<span class="op">.</span>view<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb31-4"><a href="#cb31-4"></a>    <span class="kw">using</span> type <span class="op">=</span> T;</span>
<span id="cb31-5"><a href="#cb31-5"></a><span class="op">}</span>;</span>
<span id="cb31-6"><a href="#cb31-6"></a></span>
<span id="cb31-7"><a href="#cb31-7"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Tags<span class="op">&gt;</span></span>
<span id="cb31-8"><a href="#cb31-8"></a><span class="kw">consteval</span> <span class="kw">auto</span> make_named_tuple<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info type, Tags<span class="op">...</span> tags<span class="op">)</span> <span class="op">{</span></span>
<span id="cb31-9"><a href="#cb31-9"></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> nsdms;</span>
<span id="cb31-10"><a href="#cb31-10"></a>    <span class="kw">auto</span> f <span class="op">=</span> <span class="op">[&amp;]&lt;</span><span class="kw">class</span> Tag<span class="op">&gt;(</span>Tag tag<span class="op">){</span></span>
<span id="cb31-11"><a href="#cb31-11"></a>        nsdms<span class="op">.</span>push_back<span class="op">(</span>data_member_spec<span class="op">(</span></span>
<span id="cb31-12"><a href="#cb31-12"></a>            dealias<span class="op">(^</span><span class="kw">typename</span> Tag<span class="op">::</span>type<span class="op">)</span>,</span>
<span id="cb31-13"><a href="#cb31-13"></a>            <span class="op">{.</span>name<span class="op">=</span>Tag<span class="op">::</span>name<span class="op">()}))</span>;</span>
<span id="cb31-14"><a href="#cb31-14"></a></span>
<span id="cb31-15"><a href="#cb31-15"></a>    <span class="op">}</span>;</span>
<span id="cb31-16"><a href="#cb31-16"></a>    <span class="op">(</span>f<span class="op">(</span>tags<span class="op">)</span>, <span class="op">...)</span>;</span>
<span id="cb31-17"><a href="#cb31-17"></a>    <span class="cf">return</span> define_class<span class="op">(</span>type, nsdms<span class="op">)</span>;</span>
<span id="cb31-18"><a href="#cb31-18"></a><span class="op">}</span></span>
<span id="cb31-19"><a href="#cb31-19"></a></span>
<span id="cb31-20"><a href="#cb31-20"></a><span class="kw">struct</span> R;</span>
<span id="cb31-21"><a href="#cb31-21"></a><span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>make_named_tuple<span class="op">(^</span>R, pair<span class="op">&lt;</span><span class="dt">int</span>, <span class="st">&quot;x&quot;</span><span class="op">&gt;{}</span>, pair<span class="op">&lt;</span><span class="dt">double</span>, <span class="st">&quot;y&quot;</span><span class="op">&gt;{})))</span>;</span>
<span id="cb31-22"><a href="#cb31-22"></a></span>
<span id="cb31-23"><a href="#cb31-23"></a><span class="kw">static_assert</span><span class="op">(</span>type_of<span class="op">(</span>nonstatic_data_members_of<span class="op">(^</span>R<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>
<span id="cb31-24"><a href="#cb31-24"></a><span class="kw">static_assert</span><span class="op">(</span>type_of<span class="op">(</span>nonstatic_data_members_of<span class="op">(^</span>R<span class="op">)[</span><span class="dv">1</span><span class="op">])</span> <span class="op">==</span> <span class="op">^</span><span class="dt">double</span><span class="op">)</span>;</span>
<span id="cb31-25"><a href="#cb31-25"></a></span>
<span id="cb31-26"><a href="#cb31-26"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb31-27"><a href="#cb31-27"></a>    <span class="op">[[</span><span class="at">maybe_unused</span><span class="op">]]</span> <span class="kw">auto</span> r <span class="op">=</span> R<span class="op">{.</span>x<span class="op">=</span><span class="dv">1</span>, <span class="op">.</span>y<span class="op">=</span><span class="fl">2.0</span><span class="op">}</span>;</span>
<span id="cb31-28"><a href="#cb31-28"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><a href="https://godbolt.org/z/nMx4M9sdT">On Compiler Explorer</a>.</p>
<h2 data-number="3.16" id="compile-time-ticket-counter"><span class="header-section-number">3.16</span> Compile-Time Ticket Counter<a href="#compile-time-ticket-counter" class="self-link"></a></h2>
<p>The features proposed here make it a little easier to update a ticket counter at compile time. This is not an ideal implementation (we’d prefer direct support for compile-time —– i.e., <code class="sourceCode cpp"><span class="kw">consteval</span></code> — variables), but it shows how compile-time mutable state surfaces in new ways.</p>
<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">class</span> TU_Ticket <span class="op">{</span></span>
<span id="cb32-2"><a href="#cb32-2"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">int</span> N<span class="op">&gt;</span> <span class="kw">struct</span> Helper <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">int</span> value <span class="op">=</span> N;</span>
<span id="cb32-4"><a href="#cb32-4"></a>  <span class="op">}</span>;</span>
<span id="cb32-5"><a href="#cb32-5"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb32-6"><a href="#cb32-6"></a>  <span class="kw">static</span> <span class="kw">consteval</span> <span class="dt">int</span> next<span class="op">()</span> <span class="op">{</span></span>
<span id="cb32-7"><a href="#cb32-7"></a>    <span class="co">// Search for the next incomplete Helper&lt;k&gt;.</span></span>
<span id="cb32-8"><a href="#cb32-8"></a>    std<span class="op">::</span>meta<span class="op">::</span>info r;</span>
<span id="cb32-9"><a href="#cb32-9"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>;; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb32-10"><a href="#cb32-10"></a>      r <span class="op">=</span> substitute<span class="op">(^</span>Helper, <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 class="op">})</span>;</span>
<span id="cb32-11"><a href="#cb32-11"></a>      <span class="cf">if</span> <span class="op">(</span>is_incomplete_type<span class="op">(</span>r<span class="op">))</span> <span class="cf">break</span>;</span>
<span id="cb32-12"><a href="#cb32-12"></a>    <span class="op">}</span></span>
<span id="cb32-13"><a href="#cb32-13"></a>    <span class="co">// Return the value of its member.  Calling static_data_members_of</span></span>
<span id="cb32-14"><a href="#cb32-14"></a>    <span class="co">// triggers the instantiation (i.e., completion) of Helper&lt;k&gt;.</span></span>
<span id="cb32-15"><a href="#cb32-15"></a>    <span class="cf">return</span> value_of<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;(</span>static_data_members_of<span class="op">(</span>r<span class="op">)[</span><span class="dv">0</span><span class="op">])</span>;</span>
<span id="cb32-16"><a href="#cb32-16"></a>  <span class="op">}</span></span>
<span id="cb32-17"><a href="#cb32-17"></a><span class="op">}</span>;</span>
<span id="cb32-18"><a href="#cb32-18"></a></span>
<span id="cb32-19"><a href="#cb32-19"></a><span class="dt">int</span> x <span class="op">=</span> TU_Ticket<span class="op">::</span>next<span class="op">()</span>;  <span class="co">// x initialized to 0.</span></span>
<span id="cb32-20"><a href="#cb32-20"></a><span class="dt">int</span> y <span class="op">=</span> TU_Ticket<span class="op">::</span>next<span class="op">()</span>;  <span class="co">// y initialized to 1.</span></span>
<span id="cb32-21"><a href="#cb32-21"></a><span class="dt">int</span> z <span class="op">=</span> TU_Ticket<span class="op">::</span>next<span class="op">()</span>;  <span class="co">// z initialized to 2.</span></span></code></pre></div>
</blockquote>
<p>Note that this relies on the fact that a call to <code class="sourceCode cpp">substitute</code> returns a specialization of a template, but doesn’t trigger the instantiation of that specialization. Thus, the only instantiations of <code class="sourceCode cpp">TU_Ticket<span class="op">::</span>Helper</code> occur because of the call to <code class="sourceCode cpp">nonstatic_data_members_of</code> (which is a singleton representing the lone <code class="sourceCode cpp">value</code> member).</p>
<p><a href="https://godbolt.org/z/1vEjW4sTr">On Compiler Explorer</a>.</p>
<h2 data-number="3.17" id="emulating-typeful-reflection"><span class="header-section-number">3.17</span> Emulating typeful reflection<a href="#emulating-typeful-reflection" class="self-link"></a></h2>
<p>Although we believe a single opaque <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> type to be the best and most scalable foundation for reflection, we acknowledge the desire expressed by SG7 for future support for “typeful reflection”. The following demonstrates one possible means of assembling a typeful reflection library, in which different classes of reflections are represented by distinct types, on top of the facilities proposed here.</p>
<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="co">// Represents a &#39;std::meta::info&#39; constrained by a predicate.</span></span>
<span id="cb33-2"><a href="#cb33-2"></a><span class="kw">template</span> <span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info Pred<span class="op">&gt;</span></span>
<span id="cb33-3"><a href="#cb33-3"></a>  <span class="kw">requires</span> <span class="op">(</span>type_of<span class="op">(^([:</span>Pred<span class="op">:](^</span><span class="dt">int</span><span class="op">)))</span> <span class="op">==</span> <span class="op">^</span><span class="dt">bool</span><span class="op">)</span></span>
<span id="cb33-4"><a href="#cb33-4"></a><span class="kw">struct</span> metatype <span class="op">{</span></span>
<span id="cb33-5"><a href="#cb33-5"></a>  std<span class="op">::</span>meta<span class="op">::</span>info value;</span>
<span id="cb33-6"><a href="#cb33-6"></a></span>
<span id="cb33-7"><a href="#cb33-7"></a>  <span class="co">// Construction is ill-formed unless predicate is satisfied.</span></span>
<span id="cb33-8"><a href="#cb33-8"></a>  <span class="kw">consteval</span> metatype<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">:</span> value<span class="op">(</span>r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-9"><a href="#cb33-9"></a>    <span class="cf">if</span> <span class="op">(![:</span>Pred<span class="op">:](</span>r<span class="op">))</span></span>
<span id="cb33-10"><a href="#cb33-10"></a>      <span class="cf">throw</span> <span class="st">&quot;Reflection is not a member of this metatype&quot;</span>;</span>
<span id="cb33-11"><a href="#cb33-11"></a>  <span class="op">}</span></span>
<span id="cb33-12"><a href="#cb33-12"></a></span>
<span id="cb33-13"><a href="#cb33-13"></a>  <span class="co">// Cast to &#39;std::meta::info&#39; allows values of this type to be spliced.</span></span>
<span id="cb33-14"><a href="#cb33-14"></a>  <span class="kw">consteval</span> <span class="kw">operator</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> value; <span class="op">}</span></span>
<span id="cb33-15"><a href="#cb33-15"></a></span>
<span id="cb33-16"><a href="#cb33-16"></a>  <span class="kw">static</span> <span class="kw">consteval</span> <span class="dt">bool</span> check<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">[:</span>Pred<span class="op">:](</span>r<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb33-17"><a href="#cb33-17"></a><span class="op">}</span>;</span>
<span id="cb33-18"><a href="#cb33-18"></a></span>
<span id="cb33-19"><a href="#cb33-19"></a><span class="co">// Type representing a &quot;failure to match&quot; any known metatypes.</span></span>
<span id="cb33-20"><a href="#cb33-20"></a><span class="kw">struct</span> unmatched <span class="op">{</span></span>
<span id="cb33-21"><a href="#cb33-21"></a>  <span class="kw">consteval</span> unmatched<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb33-22"><a href="#cb33-22"></a>  <span class="kw">static</span> <span class="kw">consteval</span> <span class="dt">bool</span> check<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb33-23"><a href="#cb33-23"></a><span class="op">}</span>;</span>
<span id="cb33-24"><a href="#cb33-24"></a></span>
<span id="cb33-25"><a href="#cb33-25"></a><span class="co">// Returns the given reflection &quot;enriched&quot; with a more descriptive type.</span></span>
<span id="cb33-26"><a href="#cb33-26"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Choices<span class="op">&gt;</span></span>
<span id="cb33-27"><a href="#cb33-27"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info enrich<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-28"><a href="#cb33-28"></a>  <span class="co">// Because we control the type, we know that the constructor taking info is</span></span>
<span id="cb33-29"><a href="#cb33-29"></a>  <span class="co">// the first constructor. The copy/move constructors are added at the }, so</span></span>
<span id="cb33-30"><a href="#cb33-30"></a>  <span class="co">// will be the last ones in the list.</span></span>
<span id="cb33-31"><a href="#cb33-31"></a>  std<span class="op">::</span>array ctors <span class="op">=</span> <span class="op">{</span>members_of<span class="op">(^</span>Choices, std<span class="op">::</span>meta<span class="op">::</span>is_constructor<span class="op">)[</span><span class="dv">0</span><span class="op">]...</span>,</span>
<span id="cb33-32"><a href="#cb33-32"></a>                      members_of<span class="op">(^</span>unmatched, std<span class="op">::</span>meta<span class="op">::</span>is_constructor<span class="op">)[</span><span class="dv">0</span><span class="op">]}</span>;</span>
<span id="cb33-33"><a href="#cb33-33"></a>  std<span class="op">::</span>array checks <span class="op">=</span> <span class="op">{^</span>Choices<span class="op">::</span>check<span class="op">...</span>, <span class="op">^</span>unmatched<span class="op">::</span>check<span class="op">}</span>;</span>
<span id="cb33-34"><a href="#cb33-34"></a></span>
<span id="cb33-35"><a href="#cb33-35"></a>  std<span class="op">::</span>meta<span class="op">::</span>info choice;</span>
<span id="cb33-36"><a href="#cb33-36"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="op">[</span>check, ctor<span class="op">]</span> <span class="op">:</span> std<span class="op">::</span>views<span class="op">::</span>zip<span class="op">(</span>checks, ctors<span class="op">))</span></span>
<span id="cb33-37"><a href="#cb33-37"></a>    <span class="cf">if</span> <span class="op">(</span>value_of<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>reflect_invoke<span class="op">(</span>check, <span class="op">{</span>reflect_value<span class="op">(</span>r<span class="op">)})))</span></span>
<span id="cb33-38"><a href="#cb33-38"></a>      <span class="cf">return</span> reflect_invoke<span class="op">(</span>ctor, <span class="op">{</span>reflect_value<span class="op">(</span>r<span class="op">)})</span>;</span>
<span id="cb33-39"><a href="#cb33-39"></a></span>
<span id="cb33-40"><a href="#cb33-40"></a>  std<span class="op">::</span>unreachable<span class="op">()</span>;</span>
<span id="cb33-41"><a href="#cb33-41"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>We can leverage this machinery to select different function overloads based on the “type” of reflection provided as an argument.</p>
<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">using</span> type_t <span class="op">=</span> metatype<span class="op">&lt;^</span>std<span class="op">::</span>meta<span class="op">::</span>is_type<span class="op">&gt;</span>;</span>
<span id="cb34-2"><a href="#cb34-2"></a><span class="kw">using</span> fn_t <span class="op">=</span> metatype<span class="op">&lt;^</span>std<span class="op">::</span>meta<span class="op">::</span>is_function<span class="op">&gt;</span>;</span>
<span id="cb34-3"><a href="#cb34-3"></a></span>
<span id="cb34-4"><a href="#cb34-4"></a><span class="co">// Example of a function overloaded for different &quot;types&quot; of reflections.</span></span>
<span id="cb34-5"><a href="#cb34-5"></a><span class="dt">void</span> PrintKind<span class="op">(</span>type_t<span class="op">)</span> <span class="op">{</span> std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;type&quot;</span><span class="op">)</span>; <span class="op">}</span></span>
<span id="cb34-6"><a href="#cb34-6"></a><span class="dt">void</span> PrintKind<span class="op">(</span>fn_t<span class="op">)</span> <span class="op">{</span> std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;function&quot;</span><span class="op">)</span>; <span class="op">}</span></span>
<span id="cb34-7"><a href="#cb34-7"></a><span class="dt">void</span> PrintKind<span class="op">(</span>unmatched<span class="op">)</span> <span class="op">{</span> std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;unknown kind&quot;</span><span class="op">)</span>; <span class="op">}</span></span>
<span id="cb34-8"><a href="#cb34-8"></a></span>
<span id="cb34-9"><a href="#cb34-9"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb34-10"><a href="#cb34-10"></a>  <span class="co">// Classifies any reflection as one of: Type, Function, or Unmatched.</span></span>
<span id="cb34-11"><a href="#cb34-11"></a>  <span class="kw">auto</span> enrich <span class="op">=</span> <span class="op">[](</span>std<span class="op">::</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">::</span>enrich<span class="op">&lt;</span>type_t, fn_t<span class="op">&gt;(</span>r<span class="op">)</span>; <span class="op">}</span>;</span>
<span id="cb34-12"><a href="#cb34-12"></a></span>
<span id="cb34-13"><a href="#cb34-13"></a>  <span class="co">// Demonstration of using &#39;enrich&#39; to select an overload.</span></span>
<span id="cb34-14"><a href="#cb34-14"></a>  PrintKind<span class="op">([:</span>enrich<span class="op">(^</span>main<span class="op">):])</span>;  <span class="co">// &quot;function&quot;</span></span>
<span id="cb34-15"><a href="#cb34-15"></a>  PrintKind<span class="op">([:</span>enrich<span class="op">(^</span><span class="dt">int</span><span class="op">):])</span>;   <span class="co">// &quot;type&quot;</span></span>
<span id="cb34-16"><a href="#cb34-16"></a>  PrintKind<span class="op">([:</span>enrich<span class="op">(^</span><span class="dv">3</span><span class="op">):])</span>;     <span class="co">// &quot;unknown kind&quot;</span></span>
<span id="cb34-17"><a href="#cb34-17"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Note that the <code class="sourceCode cpp">metatype</code> class can be generalized to wrap values of any literal type, or to wrap multiple values of possibly different types. This has been used, for instance, to select compile-time overloads based on: whether two integers share the same parity, the presence or absence of a value in an <code class="sourceCode cpp">optional</code>, the type of the value held by a <code class="sourceCode cpp">variant</code> or an <code class="sourceCode cpp">any</code>, or the syntactic form of a compile-time string.</p>
<p>Achieving the same in C++23, with the same generality, would require spelling the argument(s) twice: first to obtain a “classification tag” to use as a template argument, and again to call the function, i.e.,</p>
<blockquote>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1"></a>Printer<span class="op">::</span>PrintKind<span class="op">&lt;</span>classify<span class="op">(^</span><span class="dt">int</span><span class="op">)&gt;(^</span><span class="dt">int</span><span class="op">).</span></span>
<span id="cb35-2"><a href="#cb35-2"></a><span class="co">// or worse...</span></span>
<span id="cb35-3"><a href="#cb35-3"></a>fn<span class="op">&lt;</span>classify<span class="op">(</span>Arg1, Arg2, Arg3<span class="op">)&gt;(</span>Arg1, Arg2, Arg3<span class="op">).</span></span></code></pre></div>
</blockquote>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="proposed-features"><span class="header-section-number">4</span> Proposed Features<a href="#proposed-features" class="self-link"></a></h1>
<h2 data-number="4.1" id="the-reflection-operator"><span class="header-section-number">4.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 not evaluate to constant.</p>
<h3 data-number="4.1.1" id="syntax-discussion"><span class="header-section-number">4.1.1</span> Syntax discussion<a href="#syntax-discussion" class="self-link"></a></h3>
<p>The original TS landed on <code class="sourceCode cpp"><span class="cf">reflexpr</span><span class="op">(...)</span></code> as the syntax to reflect source constructs and <span class="citation" data-cites="P1240R0">[<a href="#ref-P1240R0" role="doc-biblioref">P1240R0</a>]</span> adopted that syntax as well. As more examples were discussed, it became clear that that syntax was both (a) too “heavy” and (b) insufficiently distinct from a function call. SG7 eventually agreed upon the prefix <code class="sourceCode cpp"><span class="op">^</span></code> operator. The “upward arrow” interpretation of the caret matches the “lift” or “raise” verbs that are sometimes used to describe the reflection operation in other contexts.</p>
<p>The caret already has a meaning as a binary operator in C++ (“exclusive OR”), but that is clearly not conflicting with a prefix operator. In C++/CLI (a Microsoft C++ dialect) the caret is also used as a new kind of <code class="sourceCode cpp"><em>ptr-operator</em></code> (<span>9.3.1 <a href="https://wg21.link/dcl.decl.general">[dcl.decl.general]</a></span>) to declare <a href="https://learn.microsoft.com/en-us/cpp/extensions/handle-to-object-operator-hat-cpp-component-extensions?view=msvc-170">“handles”</a>. That is also not conflicting with the use of the caret as a unary operator because C++/CLI uses the usual prefix <code class="sourceCode cpp"><span class="op">*</span></code> operator to dereference handled.</p>
<p>Apple also uses the caret in the <a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html">syntax “blocks”</a> and unfortunately we believe that does conflict with our proposed use of the caret.</p>
<p>Since the syntax discussions in SG7 landed on the use of the caret, new basic source characters have become available: <code class="sourceCode cpp"><span class="op">@</span></code>, <code><span class="op">`</span></code>, and <code><span class="op">$</span></code>. Of those, <code class="sourceCode cpp"><span class="op">@</span></code> seems the most likely substitute for the caret, because <code><span class="op">$</span></code> is used for splice-like operations in other languages and <code><span class="op">`</span></code> is suggestive of some kind of quoting (which may be useful in future metaprogramming syntax developments).</p>
<p>Another option might be the use of the backslash (<code><span class="op">\</span></code>). It currently has a meaning at the end of a line of source code, but we could still use it as a prefix operator with the constraint that the reflected operand has to start on the same source line. If we were to opt for that choice, it could make sense to use the slash (<code><span class="op">/</span></code>) as a unary operator denoting splicing (see <a href="#splicers">Splicers</a> below) so that <code><span class="op">\</span></code> would correspond to “raise” and <code><span class="op">/</span></code> would correspond to “lower”.</p>
<h2 data-number="4.2" id="splicers"><span class="header-section-number">4.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 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> in grammatical contexts that permit expressions. In type-only contexts (<span>13.8.1 <a href="https://wg21.link/temp.res.general">[temp.res.general]</a></span>/4), <code class="sourceCode cpp"><span class="op">[:</span> r <span class="op">:]</span></code> produces a type (and <code class="sourceCode cpp">r</code> must be the reflection of a type). In contexts that only permit a namespace name, <code class="sourceCode cpp"><span class="op">[:</span> r <span class="op">:]</span></code> produces a namespace (and <code class="sourceCode cpp">r</code> must be the reflection of a namespace or alias thereof).</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="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>The operand of a splicer is implicitly converted to a <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> prvalue (i.e., if the operand expression has a class type that with a conversion function to convert to <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>, splicing can still work).</p>
<p>Attempting to splice a reflection value that does not meet the requirement of the splice is ill-formed. For example:</p>
<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">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>
<h3 data-number="4.2.1" id="range-splicers"><span class="header-section-number">4.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 demonstrated 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="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-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="cb37-2"><a href="#cb37-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="cb37-3"><a href="#cb37-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="cb37-4"><a href="#cb37-4"></a></span>
<span id="cb37-5"><a href="#cb37-5"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> indices <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb37-6"><a href="#cb37-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="cb37-7"><a href="#cb37-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="cb37-8"><a href="#cb37-8"></a>    <span class="cf">return</span> indices;</span>
<span id="cb37-9"><a href="#cb37-9"></a>  <span class="op">}()</span>;</span>
<span id="cb37-10"><a href="#cb37-10"></a></span>
<span id="cb37-11"><a href="#cb37-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="cb37-12"><a href="#cb37-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="cb37-13"><a href="#cb37-13"></a><span class="op">}</span></span></code></pre></div></td>
<td><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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb38-2"><a href="#cb38-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="cb38-3"><a href="#cb38-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="cb38-4"><a href="#cb38-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="cb38-5"><a href="#cb38-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="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-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="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-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="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-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="cb41-2"><a href="#cb41-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="cb41-3"><a href="#cb41-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="cb41-4"><a href="#cb41-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="cb41-5"><a href="#cb41-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="cb41-6"><a href="#cb41-6"></a>  <span class="op">})</span>;</span>
<span id="cb41-7"><a href="#cb41-7"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>(P1240 did propose range splicers.)</p>
<h3 data-number="4.2.2" id="syntax-discussion-1"><span class="header-section-number">4.2.2</span> Syntax discussion<a href="#syntax-discussion-1" class="self-link"></a></h3>
<p>Early discussions of splice-like constructs (related to the TS design) considered using <code class="sourceCode cpp"><span class="cf">unreflexpr</span><span class="op">(...)</span></code> for that purpose. <span class="citation" data-cites="P1240R0">[<a href="#ref-P1240R0" role="doc-biblioref">P1240R0</a>]</span> adopted that option for <em>expression</em> splicing, observing that a single splicing syntax could not viably be parsed (some disambiguation is needed to distinguish types and templates). S-7 eventually agreed with the <code class="sourceCode cpp"><span class="op">[:</span> <span class="op">...</span> <span class="op">:]</span></code> syntax — with disambiguating tokens such as <code class="sourceCode cpp"><span class="kw">typename</span></code> where needed — which is a little lighter and more distinctive.</p>
<p>We propose <code class="sourceCode cpp"><span class="op">[:</span></code> and <code class="sourceCode cpp"><span class="op">:]</span></code> be single tokens rather than combinations of <code class="sourceCode cpp"><span class="op">[</span></code>, <code class="sourceCode cpp"><span class="op">]</span></code>, and <code class="sourceCode cpp"><span class="op">:</span></code>. Among others, it simplifies the handling of expressions like <code class="sourceCode cpp">arr<span class="op">[[:</span><span class="at">refl</span><span class="op">():]]</span></code>. On the flip side, it requires a special rule like the one that was made to handle <code class="sourceCode cpp"><span class="op">&lt;::</span></code> to leave the meaning of <code class="sourceCode cpp">arr<span class="op">[::</span>N<span class="op">]</span></code> unchanged and another one to avoid breaking a (somewhat useless) attribute specifier of the form <code class="sourceCode cpp"><span class="op">[[</span><span class="kw">using</span><span class="at"> ns</span><span class="op">:]]</span></code>.</p>
<p>A syntax that is delimited on the left and right is useful here because spliced expressions may involve lower-precedence operators. However, there are other possibilities. For example, now that <code><span class="op">$</span></code> is available in the basic source character set, we might consider <code class="sourceCode cpp"><span class="op">$</span><span class="op">&lt;</span><em>expr</em><span class="op">&gt;</span></code>. This is somewhat natural to those of us that have used systems where <code><span class="op">$</span></code> is used to expand placeholders in document templates. 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="op">$</span>select_type<span class="op">(</span><span class="dv">3</span><span class="op">)</span> <span class="op">*</span>ptr <span class="op">=</span> <span class="kw">nullptr</span>;</span></code></pre></div>
</blockquote>
<p>The prefixes <code class="sourceCode cpp"><span class="kw">typename</span></code> and <code class="sourceCode cpp"><span class="kw">template</span></code> are only strictly needed in some cases where the operand of the splice is a dependent expression. In our proposal, however, we only make <code class="sourceCode cpp"><span class="kw">typename</span></code> optional in the same contexts where it would be optional for qualified names with dependent name qualifiers. That has the advantage to catch unfortunate errors while keeping a single rule and helping human readers parse the intended meaning of otherwise ambiguous constructs.</p>
<h2 data-number="4.3" id="stdmetainfo"><span class="header-section-number">4.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="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></span>
<span id="cb43-2"><a href="#cb43-2"></a>  <span class="kw">namespace</span> meta <span class="op">{</span></span>
<span id="cb43-3"><a href="#cb43-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="cb43-4"><a href="#cb43-4"></a>  <span class="op">}</span></span>
<span id="cb43-5"><a href="#cb43-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>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 functions, variables or structured bindings). For example:</p>
<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="dt">int</span> x <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb44-2"><a href="#cb44-2"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb44-3"><a href="#cb44-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="cb44-4"><a href="#cb44-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="cb44-5"><a href="#cb44-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="cb44-6"><a href="#cb44-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="cb44-7"><a href="#cb44-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="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-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="cb45-2"><a href="#cb45-2"></a></span>
<span id="cb45-3"><a href="#cb45-3"></a><span class="kw">extern</span> <span class="dt">int</span> x;</span>
<span id="cb45-4"><a href="#cb45-4"></a><span class="kw">static</span> <span class="dt">int</span> y;</span>
<span id="cb45-5"><a href="#cb45-5"></a></span>
<span id="cb45-6"><a href="#cb45-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="cb45-7"><a href="#cb45-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="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1"></a><span class="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb46-2"><a href="#cb46-2"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb46-3"><a href="#cb46-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="cb46-4"><a href="#cb46-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="4.4" id="metafunctions"><span class="header-section-number">4.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="4.4.1" id="constant-evaluation-order"><span class="header-section-number">4.4.1</span> Constant evaluation order<a href="#constant-evaluation-order" class="self-link"></a></h3>
<p>In C++23, “constant evaluation” produces pure values without observable side-effects and thus the order in which constant-evaluation occurs is immaterial. In fact, while the language is designed to permit constant evaluation to happen at compile time, an implementation is not strictly required to take advantage of that possibility.</p>
<p>Some of the proposed metafunctions, however, have side-effects that have an effect of the remainder of the program. For example, we provide a <code class="sourceCode cpp">define_class</code> metafunction that provides a definition for a given class. Clearly, we want the effect of calling that metafunction to be “prompt” in a lexical-order sense. For example:</p>
<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="pp">#include </span><span class="im">&lt;meta&gt;</span></span>
<span id="cb47-2"><a href="#cb47-2"></a><span class="kw">struct</span> S;</span>
<span id="cb47-3"><a href="#cb47-3"></a></span>
<span id="cb47-4"><a href="#cb47-4"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb47-5"><a href="#cb47-5"></a>  <span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>define_class<span class="op">(^</span>S, <span class="op">{})))</span>;</span>
<span id="cb47-6"><a href="#cb47-6"></a>  S s;  <span class="co">// S should be defined at this point.</span></span>
<span id="cb47-7"><a href="#cb47-7"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Hence this proposal also introduces constraints on constant evaluation as follows…</p>
<p>First, we identify a subset of manifestly constant-evaluated expressions and conversions characterized by the fact that their evaluation must occur and must succeed in a valid C++ program: We call these <em>plainly constant-evaluated</em>. We require that a programmer can count on those evaluations occurring exactly once and completing at translation time.</p>
<p>Second, we sequence plainly constant-evaluated expressions and conversions within the lexical order. Specifically, we require that the evaluation of a plainly constant-evaluated expression or conversion occurs before the implementation checks the validity of source constructs lexically following that expression or conversion.</p>
<p>Those constraints are mostly intuitive, but they are a significant change to the underlying principles of the current standard in this respect.</p>
<p><span class="citation" data-cites="P2758R1">[<a href="#ref-P2758R1" role="doc-biblioref">P2758R1</a>]</span> (“Emitting messages at compile time”) also has to deal with side effects during constant evaluation. However, those effects (“output”) are of a slightly different nature in the sense that they can be buffered until a manifestly constant-evaluated expression/conversion has completed. “Buffering” a class type completion is not practical (e.g., because other metafunctions may well depend on the completed class type). Still, we are not aware of incompatibilities between our proposal and <span class="citation" data-cites="P2758R1">[<a href="#ref-P2758R1" role="doc-biblioref">P2758R1</a>]</span>.</p>
<h3 data-number="4.4.2" id="error-handling-in-reflection"><span class="header-section-number">4.4.2</span> Error-Handling in Reflection<a href="#error-handling-in-reflection" class="self-link"></a></h3>
<p>One important question we have to answer is: How do we handle errors in reflection metafunctions? For example, what does <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>template_of<span class="op">(^</span><span class="dt">int</span><span class="op">)</span></code> do? <code class="sourceCode cpp"><span class="op">^</span><span class="dt">int</span></code> is a reflection of a type, but that type is not a specialization of a template, so there is no valid reflected template for us to return.</p>
<p>There are a few options available to us today:</p>
<ol type="1">
<li>This fails to be a constant expression (unspecified mechanism).</li>
<li>This returns an invalid reflection (similar to <code class="sourceCode cpp">NaN</code> for floating point) which carries source location info and some useful message. (This was the approach suggested in P1240.)</li>
<li>This returns <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info, E<span class="op">&gt;</span></code> for some reflection-specific error type <code class="sourceCode cpp">E</code> which carries source location info and some useful message (this could be just <code class="sourceCode cpp">info</code> but probably should not be).</li>
<li>This throws an exception of type <code class="sourceCode cpp">E</code> (which requires allowing exceptions to work during <code class="sourceCode cpp"><span class="kw">constexpr</span></code> evaluation, such that an uncaught exception would fail to be a constant exception).</li>
</ol>
<p>The immediate downside of (2), yielding a <code class="sourceCode cpp">NaN</code>-like reflection for <code class="sourceCode cpp">template_of<span class="op">(^</span><span class="dt">int</span><span class="op">)</span></code> is what we do for those functions that need to return a range. That is, what does <code class="sourceCode cpp">template_arguments_of<span class="op">(^</span><span class="dt">int</span><span class="op">)</span></code> return?</p>
<ol type="1">
<li>This fails to be a constant expression (unspecified mechanism).</li>
<li>This returns 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> containing one invalid reflection.</li>
<li>This returns a <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span>, E<span class="op">&gt;</span></code>.</li>
<li>This throws an exception of type <code class="sourceCode cpp">E</code>.</li>
</ol>
<p>Having range-based functions return a single invalid reflection would make for awkward error handling code. Using <code class="sourceCode cpp">std<span class="op">::</span>expected</code> or exceptions for error handling allow for a consistent, more straightforward interface.</p>
<p>This becomes another situation where we need to decide an error handling mechanism between exceptions and not exceptions, although importantly in this context a lot of usual concerns about exceptions do not apply:</p>
<ul>
<li>there is no runtime (so concerns about runtime performance, object file size, etc. do not exist), and</li>
<li>there is no runtime (so concerns about code evolving to add a new uncaught exception type do not apply)</li>
</ul>
<p>There is one interesting example to consider to decide between <code class="sourceCode cpp">std<span class="op">::</span>expected</code> and exceptions here:</p>
<blockquote>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-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="cb48-2"><a href="#cb48-2"></a>  <span class="kw">requires</span> <span class="op">(</span>template_of<span class="op">(^</span>T<span class="op">)</span> <span class="op">==</span> <span class="op">^</span>std<span class="op">::</span>optional<span class="op">)</span></span>
<span id="cb48-3"><a href="#cb48-3"></a><span class="dt">void</span> foo<span class="op">()</span>;</span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">template_of</code> returns an <code class="sourceCode cpp">excepted<span class="op">&lt;</span>info, E<span class="op">&gt;</span></code>, then <code class="sourceCode cpp">foo<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> is a substitution failure — <code class="sourceCode cpp">expected<span class="op">&lt;</span>T, E<span class="op">&gt;</span></code> is equality-comparable to <code class="sourceCode cpp">T</code>, that comparison would evaluate to <code class="sourceCode cpp"><span class="kw">false</span></code> but still be a constant expression.</p>
<p>If <code class="sourceCode cpp">template_of</code> returns <code class="sourceCode cpp">info</code> but throws an exception, then <code class="sourceCode cpp">foo<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> would cause that exception to be uncaught, which would make the comparison not a constant expression. This actually makes the constraint ill-formed - not a substitution failure. In order to have <code class="sourceCode cpp">foo<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> be a substitution failure, either the constraint would have to first check that <code class="sourceCode cpp">T</code> is a template or we would have to change the language rule that requires constraints to be constant expressions (we would of course still keep the requirement that the constraint is a <code class="sourceCode cpp"><span class="dt">bool</span></code>).</p>
<p>The other thing to consider are compiler modes that disable exception support (like <code class="sourceCode cpp"><span class="op">-</span>fno<span class="op">-</span>exceptions</code> in GCC and Clang). Today, implementations reject using <code class="sourceCode cpp"><span class="cf">try</span></code>, <code class="sourceCode cpp"><span class="cf">catch</span></code>, or <code class="sourceCode cpp"><span class="cf">throw</span></code> at all when such modes are enabled. With support for <code class="sourceCode cpp"><span class="kw">constexpr</span></code> exceptions, implementations would have to come up with a strategy for how to support compile-time exceptions — probably by only allowing them in <code class="sourceCode cpp"><span class="kw">consteval</span></code> functions (including <code class="sourceCode cpp"><span class="kw">constexpr</span></code> function templates that were propagated to <code class="sourceCode cpp"><span class="kw">consteval</span></code>).</p>
<p>Despite these concerns (and the requirement of a whole new language feature), we believe that exceptions will be the more user-friendly choice for error handling here, simply because exceptions are more ergonomic to use than <code class="sourceCode cpp">std<span class="op">::</span>expected</code> (even if we adopt language features that make this type easier to use - like pattern matching and a control flow operator).</p>
<h3 data-number="4.4.3" id="handling-aliases"><span class="header-section-number">4.4.3</span> Handling Aliases<a href="#handling-aliases" class="self-link"></a></h3>
<p>Consider</p>
<blockquote>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1"></a><span class="kw">using</span> A <span class="op">=</span> <span class="dt">int</span>;</span></code></pre></div>
</blockquote>
<p>In C++ today, <code class="sourceCode cpp">A</code> and <code class="sourceCode cpp"><span class="dt">int</span></code> can be used interchangeably and there is no distinction between the two types. With reflection as proposed in this paper, that will no longer be the case. <code class="sourceCode cpp"><span class="op">^</span>A</code> yields a reflection of an alias to <code class="sourceCode cpp"><span class="dt">int</span></code>, while <code class="sourceCode cpp"><span class="op">^</span><span class="dt">int</span></code> yields a reflection of <code class="sourceCode cpp"><span class="dt">int</span></code>. <code class="sourceCode cpp"><span class="op">^</span>A <span class="op">==</span> <span class="op">^</span><span class="dt">int</span></code> evaluates to <code class="sourceCode cpp"><span class="kw">false</span></code>, but there will be a way to strip aliases - so <code class="sourceCode cpp">dealias<span class="op">(^</span>A<span class="op">)</span> <span class="op">==</span> <span class="op">^</span><span class="dt">int</span></code> evaluates to <code class="sourceCode cpp"><span class="kw">true</span></code>.</p>
<p>This opens up the question of how various other metafunctions handle aliases and it is worth going over a few examples:</p>
<blockquote>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1"></a><span class="kw">using</span> A <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb50-2"><a href="#cb50-2"></a><span class="kw">using</span> B <span class="op">=</span> std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>;</span>
<span id="cb50-3"><a href="#cb50-3"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">using</span> C <span class="op">=</span> std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span></code></pre></div>
</blockquote>
<p>This paper is proposing that:</p>
<ul>
<li><code class="sourceCode cpp">is_type<span class="op">(^</span>A<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. <code class="sourceCode cpp"><span class="op">^</span>A</code> is an alias, but it’s an alias to a type, and if this evaluated as <code class="sourceCode cpp"><span class="kw">false</span></code> then everyone would have to <code class="sourceCode cpp">dealias</code> everything all the time.</li>
<li><code class="sourceCode cpp">has_template_arguments<span class="op">(^</span>B<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code> while <code class="sourceCode cpp">has_template_arguments<span class="op">(^</span>C<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. Even though <code class="sourceCode cpp">B</code> is an alias to a type that itself has template arguments (<code class="sourceCode cpp">unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>), <code class="sourceCode cpp">B</code> itself is simply a type alias and does not. This reflects the actual usage.</li>
<li>Meanwhile, <code class="sourceCode cpp">template_arguments_of<span class="op">(^</span>C<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span></code> yields <code class="sourceCode cpp"><span class="op">{^</span><span class="dt">int</span><span class="op">}</span></code> while <code class="sourceCode cpp">template_arguments_of<span class="op">(^</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span></code> yields <code class="sourceCode cpp"><span class="op">{^</span><span class="dt">int</span>, <span class="op">^</span>std<span class="op">::</span>default_deleter<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;}</span></code>. This is <code class="sourceCode cpp">C</code> has its own template arguments that can be reflected on.</li>
</ul>
<h3 data-number="4.4.4" id="freestanding-implementations"><span class="header-section-number">4.4.4</span> Freestanding implementations<a href="#freestanding-implementations" class="self-link"></a></h3>
<p>Several important metafunctions, such as <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>_nonstatic_data_members_of</code>, return a <code class="sourceCode cpp">std<span class="op">::</span>vector</code> value. Unfortunately, that means that they are currently not usable in a freestanding environment. That is an highly undesirable limitation that we believe should be addressed by imbuing freestanding implementations with a more restricted <code class="sourceCode cpp">std<span class="op">::</span>vector</code> (e.g., one that can only allocate at compile time).</p>
<h3 data-number="4.4.5" id="synopsis"><span class="header-section-number">4.4.5</span> Synopsis<a href="#synopsis" class="self-link"></a></h3>
<p>Here is a synopsis for the proposed library API. The functions will be explained below.</p>
<blockquote>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb51-2"><a href="#cb51-2"></a>  <span class="co">// <a href="#name_of-display_name_of-source_location_of">name and location</a></span></span>
<span id="cb51-3"><a href="#cb51-3"></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="cb51-4"><a href="#cb51-4"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> qualified_name_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view;</span>
<span id="cb51-5"><a href="#cb51-5"></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="cb51-6"><a href="#cb51-6"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> source_location_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> source_location;</span>
<span id="cb51-7"><a href="#cb51-7"></a></span>
<span id="cb51-8"><a href="#cb51-8"></a>  <span class="co">// <a href="#type_of-parent_of-dealias">type queries</a></span></span>
<span id="cb51-9"><a href="#cb51-9"></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="cb51-10"><a href="#cb51-10"></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="cb51-11"><a href="#cb51-11"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> dealias<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb51-12"><a href="#cb51-12"></a></span>
<span id="cb51-13"><a href="#cb51-13"></a>  <span class="co">// <a href="#template_of-template_arguments_of">template queries</a></span></span>
<span id="cb51-14"><a href="#cb51-14"></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="cb51-15"><a href="#cb51-15"></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="cb51-16"><a href="#cb51-16"></a></span>
<span id="cb51-17"><a href="#cb51-17"></a>  <span class="co">// <a href="#members_of-static_data_members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of">member queries</a></span></span>
<span id="cb51-18"><a href="#cb51-18"></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="cb51-19"><a href="#cb51-19"></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="cb51-20"><a href="#cb51-20"></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="cb51-21"><a href="#cb51-21"></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>
<span id="cb51-22"><a href="#cb51-22"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> static_data_members_of<span class="op">(</span>info class_type<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb51-23"><a href="#cb51-23"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> nonstatic_data_members_of<span class="op">(</span>info class_type<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb51-24"><a href="#cb51-24"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> subobjects_of<span class="op">(</span>info class_type<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb51-25"><a href="#cb51-25"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> enumerators_of<span class="op">(</span>info enum_type<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb51-26"><a href="#cb51-26"></a></span>
<span id="cb51-27"><a href="#cb51-27"></a>  <span class="co">// <a href="#substitute">substitute</a></span></span>
<span id="cb51-28"><a href="#cb51-28"></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="cb51-29"><a href="#cb51-29"></a></span>
<span id="cb51-30"><a href="#cb51-30"></a>  <span class="co">// <a href="#reflect_invoke">reflect_invoke</a></span></span>
<span id="cb51-31"><a href="#cb51-31"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> reflect_invoke<span class="op">(</span>info target, 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="cb51-32"><a href="#cb51-32"></a></span>
<span id="cb51-33"><a href="#cb51-33"></a>   <span class="co">// <a href="#value_oft">value_of<T></a></span></span>
<span id="cb51-34"><a href="#cb51-34"></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="cb51-35"><a href="#cb51-35"></a>    <span class="kw">consteval</span> <span class="kw">auto</span> value_of<span class="op">(</span>info<span class="op">)</span> <span class="op">-&gt;</span> T;</span>
<span id="cb51-36"><a href="#cb51-36"></a></span>
<span id="cb51-37"><a href="#cb51-37"></a>  <span class="co">// <a href="#test_type-test_types">test_type</a></span></span>
<span id="cb51-38"><a href="#cb51-38"></a>  <span class="kw">consteval</span> <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>
<span id="cb51-39"><a href="#cb51-39"></a>  <span class="kw">consteval</span> <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>
<span id="cb51-40"><a href="#cb51-40"></a></span>
<span id="cb51-41"><a href="#cb51-41"></a>  <span class="co">// other type predicates (see <a href="#meta.reflection.queries-reflection-queries">the wording</a>)</span></span>
<span id="cb51-42"><a href="#cb51-42"></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="cb51-43"><a href="#cb51-43"></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="cb51-44"><a href="#cb51-44"></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="cb51-45"><a href="#cb51-45"></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="cb51-46"><a href="#cb51-46"></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="cb51-47"><a href="#cb51-47"></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="cb51-48"><a href="#cb51-48"></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="cb51-49"><a href="#cb51-49"></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="cb51-50"><a href="#cb51-50"></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="cb51-51"><a href="#cb51-51"></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="cb51-52"><a href="#cb51-52"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_bit_field<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-53"><a href="#cb51-53"></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="cb51-54"><a href="#cb51-54"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> has_internal_linkage<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-55"><a href="#cb51-55"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> has_external_linkage<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-56"><a href="#cb51-56"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> has_linkage<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-57"><a href="#cb51-57"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_class_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-58"><a href="#cb51-58"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_namespace_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-59"><a href="#cb51-59"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_nonstatic_data_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-60"><a href="#cb51-60"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_static_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-61"><a href="#cb51-61"></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="cb51-62"><a href="#cb51-62"></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="cb51-63"><a href="#cb51-63"></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="cb51-64"><a href="#cb51-64"></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="cb51-65"><a href="#cb51-65"></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="cb51-66"><a href="#cb51-66"></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="cb51-67"><a href="#cb51-67"></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="cb51-68"><a href="#cb51-68"></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="cb51-69"><a href="#cb51-69"></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="cb51-70"><a href="#cb51-70"></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="cb51-71"><a href="#cb51-71"></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="cb51-72"><a href="#cb51-72"></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="cb51-73"><a href="#cb51-73"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_concept<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-74"><a href="#cb51-74"></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="cb51-75"><a href="#cb51-75"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_constructor<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-76"><a href="#cb51-76"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_destructor<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-77"><a href="#cb51-77"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> is_special_member<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb51-78"><a href="#cb51-78"></a></span>
<span id="cb51-79"><a href="#cb51-79"></a>  <span class="co">// <a href="#reflect_value">reflect_value</a></span></span>
<span id="cb51-80"><a href="#cb51-80"></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="cb51-81"><a href="#cb51-81"></a>    <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="cb51-82"><a href="#cb51-82"></a></span>
<span id="cb51-83"><a href="#cb51-83"></a>  <span class="co">// <a href="#data_member_spec-define_class">define_class</a></span></span>
<span id="cb51-84"><a href="#cb51-84"></a>  <span class="kw">struct</span> data_member_options_t;</span>
<span id="cb51-85"><a href="#cb51-85"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> data_member_spec<span class="op">(</span>info class_type,</span>
<span id="cb51-86"><a href="#cb51-86"></a>                                  data_member_options_t options <span class="op">=</span> <span class="op">{})</span> <span class="op">-&gt;</span> info;</span>
<span id="cb51-87"><a href="#cb51-87"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> define_class<span class="op">(</span>info class_type, 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="cb51-88"><a href="#cb51-88"></a></span>
<span id="cb51-89"><a href="#cb51-89"></a>  <span class="co">// <a href="#data-layout-reflection">data layout</a></span></span>
<span id="cb51-90"><a href="#cb51-90"></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="cb51-91"><a href="#cb51-91"></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="cb51-92"><a href="#cb51-92"></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="cb51-93"><a href="#cb51-93"></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="cb51-94"><a href="#cb51-94"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> alignment_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="cb51-95"><a href="#cb51-95"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h3 data-number="4.4.6" id="name_of-display_name_of-source_location_of"><span class="header-section-number">4.4.6</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="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb52-2"><a href="#cb52-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="cb52-3"><a href="#cb52-3"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> qualified_name_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view;</span>
<span id="cb52-4"><a href="#cb52-4"></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="cb52-5"><a href="#cb52-5"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> source_location_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> source_location;</span>
<span id="cb52-6"><a href="#cb52-6"></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> and <code class="sourceCode cpp">qualified_name_of<span class="op">(</span>r<span class="op">)</span></code> return a <code class="sourceCode cpp">string_view</code> holding the unqualified and qualified name of <code class="sourceCode cpp">X</code>, respectively. 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="4.4.7" id="type_of-parent_of-dealias"><span class="header-section-number">4.4.7</span> <code class="sourceCode cpp">type_of</code>, <code class="sourceCode cpp">parent_of</code>, <code class="sourceCode cpp">dealias</code><a href="#type_of-parent_of-dealias" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb53-2"><a href="#cb53-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="cb53-3"><a href="#cb53-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="cb53-4"><a href="#cb53-4"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> dealias<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb53-5"><a href="#cb53-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. If <code class="sourceCode cpp">r</code> is already a type, <code class="sourceCode cpp">type_of<span class="op">(</span>r<span class="op">)</span></code> is not a constant expression. This can be used to implement the C <code class="sourceCode cpp"><span class="ex">typeof</span></code> feature (which works on both types and expressions and strips qualifiers):</p>
<blockquote>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> do_typeof<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info r<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="cb54-2"><a href="#cb54-2"></a>  <span class="cf">return</span> remove_cvref<span class="op">(</span>is_type<span class="op">(</span>r<span class="op">)</span> <span class="op">?</span> r <span class="op">:</span> type_of<span class="op">(</span>r<span class="op">))</span>;</span>
<span id="cb54-3"><a href="#cb54-3"></a><span class="op">}</span></span>
<span id="cb54-4"><a href="#cb54-4"></a></span>
<span id="cb54-5"><a href="#cb54-5"></a><span class="pp">#define typeof</span><span class="op">(</span>e<span class="op">)</span><span class="pp"> </span><span class="op">[:</span><span class="pp"> </span>do_typeof<span class="op">(^</span>e<span class="op">)</span><span class="pp"> </span><span class="op">:]</span></span></code></pre></div>
</blockquote>
<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.</p>
<p>If <code class="sourceCode cpp">r</code> designates an alias, <code class="sourceCode cpp">dealias<span class="op">(</span>r<span class="op">)</span></code> designates the underlying entity. Otherwise, <code class="sourceCode cpp">dealias<span class="op">(</span>r<span class="op">)</span></code> produces <code class="sourceCode cpp">r</code>. <code class="sourceCode cpp">dealias</code> is recursive - it strips all aliases:</p>
<blockquote>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1"></a><span class="kw">using</span> X <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb55-2"><a href="#cb55-2"></a><span class="kw">using</span> Y <span class="op">=</span> X;</span>
<span id="cb55-3"><a href="#cb55-3"></a><span class="kw">static_assert</span><span class="op">(</span>dealias<span class="op">(^</span><span class="dt">int</span><span class="op">)</span> <span class="op">==</span> <span class="op">^</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb55-4"><a href="#cb55-4"></a><span class="kw">static_assert</span><span class="op">(</span>dealias<span class="op">(^</span>X<span class="op">)</span> <span class="op">==</span> <span class="op">^</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb55-5"><a href="#cb55-5"></a><span class="kw">static_assert</span><span class="op">(</span>dealias<span class="op">(^</span>Y<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="4.4.8" id="template_of-template_arguments_of"><span class="header-section-number">4.4.8</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="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb56-2"><a href="#cb56-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="cb56-3"><a href="#cb56-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="cb56-4"><a href="#cb56-4"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">r</code> is a reflection designated 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. 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="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-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="cb57-2"><a href="#cb57-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="cb57-3"><a href="#cb57-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="4.4.9" id="members_of-static_data_members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of"><span class="header-section-number">4.4.9</span> <code class="sourceCode cpp">members_of</code>, <code class="sourceCode cpp">static_data_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-static_data_members_of-nonstatic_data_members_of-bases_of-enumerators_of-subobjects_of" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb58-2"><a href="#cb58-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="cb58-3"><a href="#cb58-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="cb58-4"><a href="#cb58-4"></a></span>
<span id="cb58-5"><a href="#cb58-5"></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="cb58-6"><a href="#cb58-6"></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>
<span id="cb58-7"><a href="#cb58-7"></a></span>
<span id="cb58-8"><a href="#cb58-8"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> static_data_members_of<span class="op">(</span>info class_type<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="cb58-9"><a href="#cb58-9"></a>    <span class="cf">return</span> members_of<span class="op">(</span>class_type, is_variable<span class="op">)</span>;</span>
<span id="cb58-10"><a href="#cb58-10"></a>  <span class="op">}</span></span>
<span id="cb58-11"><a href="#cb58-11"></a></span>
<span id="cb58-12"><a href="#cb58-12"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> nonstatic_data_members_of<span class="op">(</span>info class_type<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="cb58-13"><a href="#cb58-13"></a>    <span class="cf">return</span> members_of<span class="op">(</span>class_type, is_nonstatic_data_member<span class="op">)</span>;</span>
<span id="cb58-14"><a href="#cb58-14"></a>  <span class="op">}</span></span>
<span id="cb58-15"><a href="#cb58-15"></a></span>
<span id="cb58-16"><a href="#cb58-16"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> subobjects_of<span class="op">(</span>info class_type<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="cb58-17"><a href="#cb58-17"></a>    <span class="kw">auto</span> subobjects <span class="op">=</span> bases_of<span class="op">(</span>class_type<span class="op">)</span>;</span>
<span id="cb58-18"><a href="#cb58-18"></a>    subobjects<span class="op">.</span>append_range<span class="op">(</span>nonstatic_data_members_of<span class="op">(</span>class_type<span class="op">))</span>;</span>
<span id="cb58-19"><a href="#cb58-19"></a>    <span class="cf">return</span> subobjects;</span>
<span id="cb58-20"><a href="#cb58-20"></a>  <span class="op">}</span></span>
<span id="cb58-21"><a href="#cb58-21"></a></span>
<span id="cb58-22"><a href="#cb58-22"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> enumerators_of<span class="op">(</span>info enum_type<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb58-23"><a href="#cb58-23"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>The template <code class="sourceCode cpp">members_of</code> returns a vector of reflections representing the direct members of the class type represented by its first argument. Any nonstatic data members appear in declaration order within that vector. Anonymous unions appear as a nonstatic data member of corresponding union type. If any <code class="sourceCode cpp">Filters<span class="op">...</span></code> argument is specified, a member is dropped from the result if any filter applied to that members reflection returns <code class="sourceCode cpp"><span class="kw">false</span></code>. E.g., <code class="sourceCode cpp">members_of<span class="op">(^</span>C, std<span class="op">::</span>meta<span class="op">::</span>is_type<span class="op">)</span></code> will only return types nested in the definition of <code class="sourceCode cpp">C</code> and <code class="sourceCode cpp">members_of<span class="op">(^</span>C, std<span class="op">::</span>meta<span class="op">::</span>is_type, std<span class="op">::</span>meta<span class="op">::</span>is_variable<span class="op">)</span></code> will return an empty vector since a member cannot be both a type and a variable.</p>
<p>The template <code class="sourceCode cpp">bases_of</code> returns the direct base classes of the class type represented by its first argument, in declaration order.</p>
<p><code class="sourceCode cpp">enumerators_of</code> returns the enumerator constants of the indicated enumeration type in declaration order.</p>
<h3 data-number="4.4.10" id="substitute"><span class="header-section-number">4.4.10</span> <code class="sourceCode cpp">substitute</code><a href="#substitute" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb59-2"><a href="#cb59-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="cb59-3"><a href="#cb59-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 obtained by substituting the given arguments in the template. If the template is a concept template, the result is a reflection of a constant of type <code class="sourceCode cpp"><span class="dt">bool</span></code>.</p>
<p>For example:</p>
<blockquote>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-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="cb60-2"><a href="#cb60-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.</p>
<p>Note that the template is only substituted, not instantiated. For example:</p>
<blockquote>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-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="cb61-2"><a href="#cb61-2"></a></span>
<span id="cb61-3"><a href="#cb61-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="cb61-4"><a href="#cb61-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="4.4.11" id="reflect_invoke"><span class="header-section-number">4.4.11</span> <code class="sourceCode cpp">reflect_invoke</code><a href="#reflect_invoke" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb62-2"><a href="#cb62-2"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> reflect_invoke<span class="op">(</span>info target, 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="cb62-3"><a href="#cb62-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This metafunction produces a reflection of the value returned by a call expression.</p>
<p>Letting <code class="sourceCode cpp">F</code> be the entity reflected by <code class="sourceCode cpp">target</code>, and <code class="sourceCode cpp">A_0, <span class="op">...</span>, A_n</code> be the sequence of entities reflected by the values held by <code class="sourceCode cpp">args</code>: if the expression <code class="sourceCode cpp">F<span class="op">(</span>A_0, <span class="op">...</span>, A_N<span class="op">)</span></code> is a well-formed constant expression evaluating to a type that is not <code class="sourceCode cpp"><span class="dt">void</span></code>, and if every value in <code class="sourceCode cpp">args</code> is a reflection of a constant value, then <code class="sourceCode cpp">reflect_invoke<span class="op">(</span>target, args<span class="op">)</span></code> evaluates to a reflection of the constant value <code class="sourceCode cpp">F<span class="op">(</span>A_0, <span class="op">...</span>, A_N<span class="op">)</span></code>.</p>
<p>For all other invocations, <code class="sourceCode cpp">reflect_invoke<span class="op">(</span>target, args<span class="op">)</span></code> is ill-formed.</p>
<h3 data-number="4.4.12" id="value_oft"><span class="header-section-number">4.4.12</span> <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;</span></code><a href="#value_oft" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb63"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb63-1"><a href="#cb63-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb63-2"><a href="#cb63-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> value_of<span class="op">(</span>info<span class="op">)</span> <span class="op">-&gt;</span> T;</span>
<span id="cb63-3"><a href="#cb63-3"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<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">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to that constant value.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection for a variable of non-reference type <code class="sourceCode cpp">T</code>, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&amp;&gt;(</span>r<span class="op">)</span></code> and <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&amp;&gt;(</span>r<span class="op">)</span></code> are lvalues referring to that variable. If the variable is usable in constant expressions [expr.const], <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to its value.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection for a variable of reference type <code class="sourceCode cpp">T</code> usable in constant-expressions, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>T<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to that reference.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection of an enumerator constant of type <code class="sourceCode cpp">E</code>, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>E<span class="op">&gt;(</span>r<span class="op">)</span></code> evaluates to the value of that enumerator.</p>
<p>If <code class="sourceCode cpp">r</code> is a reflection of a non-bit-field non-reference non-static member of type <code class="sourceCode cpp">M</code> in a class <code class="sourceCode cpp">C</code>, <code class="sourceCode cpp">value_of<span class="op">&lt;</span>M C<span class="op">::*&gt;(</span>r<span class="op">)</span></code> is the pointer-to-member value for that nonstatic member.</p>
<p>For other reflection values <code class="sourceCode cpp">r</code>, <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>The function template <code class="sourceCode cpp">value_of</code> may feel similar to splicers, but unlike splicers it does not require its operand to be a constant-expression itself. Also unlike splicers, it requires knowledge of the type associated with the entity reflected by its operand.</p>
<h3 data-number="4.4.13" id="test_type-test_types"><span class="header-section-number">4.4.13</span> <code class="sourceCode cpp">test_type</code>, <code class="sourceCode cpp">test_types</code><a href="#test_type-test_types" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb64"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb64-1"><a href="#cb64-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb64-2"><a href="#cb64-2"></a>  <span class="kw">consteval</span> <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="cb64-3"><a href="#cb64-3"></a>    <span class="cf">return</span> test_types<span class="op">(</span>templ, <span class="op">{</span>type<span class="op">})</span>;</span>
<span id="cb64-4"><a href="#cb64-4"></a>  <span class="op">}</span></span>
<span id="cb64-5"><a href="#cb64-5"></a></span>
<span id="cb64-6"><a href="#cb64-6"></a>  <span class="kw">consteval</span> <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="cb64-7"><a href="#cb64-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="cb64-8"><a href="#cb64-8"></a>  <span class="op">}</span></span>
<span id="cb64-9"><a href="#cb64-9"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This utility translates existing metaprogramming predicates (expressed as constexpr variable templates or concept templates) to the reflection domain. For example:</p>
<blockquote>
<div class="sourceCode" id="cb65"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb65-1"><a href="#cb65-1"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb65-2"><a href="#cb65-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="4.4.14" id="reflect_value"><span class="header-section-number">4.4.14</span> <code class="sourceCode cpp">reflect_value</code><a href="#reflect_value" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb66"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb66-1"><a href="#cb66-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb66-2"><a href="#cb66-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="cb66-3"><a href="#cb66-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="4.4.15" id="data_member_spec-define_class"><span class="header-section-number">4.4.15</span> <code class="sourceCode cpp">data_member_spec</code>, <code class="sourceCode cpp">define_class</code><a href="#data_member_spec-define_class" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb67"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb67-1"><a href="#cb67-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb67-2"><a href="#cb67-2"></a>  <span class="kw">struct</span> data_member_options_t <span class="op">{</span></span>
<span id="cb67-3"><a href="#cb67-3"></a>    optional<span class="op">&lt;</span>string_view<span class="op">&gt;</span> name;</span>
<span id="cb67-4"><a href="#cb67-4"></a>    <span class="dt">bool</span> is_static <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb67-5"><a href="#cb67-5"></a>    optional<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> alignment;</span>
<span id="cb67-6"><a href="#cb67-6"></a>    optional<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> width;</span>
<span id="cb67-7"><a href="#cb67-7"></a>  <span class="op">}</span>;</span>
<span id="cb67-8"><a href="#cb67-8"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> data_member_spec<span class="op">(</span>info type,</span>
<span id="cb67-9"><a href="#cb67-9"></a>                                  data_member_options_t options <span class="op">=</span> <span class="op">{})</span> <span class="op">-&gt;</span> info;</span>
<span id="cb67-10"><a href="#cb67-10"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> define_class<span class="op">(</span>info class_type, 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="cb67-11"><a href="#cb67-11"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">data_member_spec</code> returns a reflection of a description of a data member of given type. Optional alignment, bit-field-width, static-ness, and name can be provided as well. If no <code class="sourceCode cpp">name</code> is provided, the name of the data member is unspecified. If <code class="sourceCode cpp">is_static</code> is <code class="sourceCode cpp"><span class="kw">true</span></code>, the data member is declared <code class="sourceCode cpp"><span class="kw">static</span></code>.</p>
<p><code class="sourceCode cpp">define_class</code> takes the reflection of an incomplete class/struct/union type and a range of reflections of data member descriptions and it completes the given class type with data members as described (in the given order). The given reflection is returned. For now, only data member reflections are supported (via <code class="sourceCode cpp">data_member_spec</code>) but the API takes in a range of <code class="sourceCode cpp">info</code> anticipating expanding this in the near future.</p>
<p>For example:</p>
<blockquote>
<div class="sourceCode" id="cb68"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb68-1"><a href="#cb68-1"></a><span class="kw">union</span> U;</span>
<span id="cb68-2"><a href="#cb68-2"></a><span class="kw">static_assert</span><span class="op">(</span>is_type<span class="op">(</span>define_class<span class="op">(^</span>U, <span class="op">{</span></span>
<span id="cb68-3"><a href="#cb68-3"></a>  data_member_spec<span class="op">(^</span><span class="dt">int</span><span class="op">)</span>,</span>
<span id="cb68-4"><a href="#cb68-4"></a>  data_member_spec<span class="op">(^</span><span class="dt">char</span><span class="op">)</span>,</span>
<span id="cb68-5"><a href="#cb68-5"></a>  data_member_spec<span class="op">(^</span><span class="dt">double</span><span class="op">)</span>,</span>
<span id="cb68-6"><a href="#cb68-6"></a><span class="op">})))</span>;</span>
<span id="cb68-7"><a href="#cb68-7"></a></span>
<span id="cb68-8"><a href="#cb68-8"></a><span class="co">// U is now defined to the equivalent of</span></span>
<span id="cb68-9"><a href="#cb68-9"></a><span class="co">// union U {</span></span>
<span id="cb68-10"><a href="#cb68-10"></a><span class="co">//   int <em>_0</em>;</span></span>
<span id="cb68-11"><a href="#cb68-11"></a><span class="co">//   char <em>_1</em>;</span></span>
<span id="cb68-12"><a href="#cb68-12"></a><span class="co">//   double <em>_2</em>;</span></span>
<span id="cb68-13"><a href="#cb68-13"></a><span class="co">// };</span></span>
<span id="cb68-14"><a href="#cb68-14"></a></span>
<span id="cb68-15"><a href="#cb68-15"></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>
<span id="cb68-16"><a href="#cb68-16"></a><span class="kw">constexpr</span> <span class="kw">auto</span> U <span class="op">=</span> define_class<span class="op">(^</span>S<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, <span class="op">{</span></span>
<span id="cb68-17"><a href="#cb68-17"></a>  data_member_spec<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="cb68-18"><a href="#cb68-18"></a>  data_member_spec<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="cb68-19"><a href="#cb68-19"></a><span class="op">})</span>;</span>
<span id="cb68-20"><a href="#cb68-20"></a></span>
<span id="cb68-21"><a href="#cb68-21"></a><span class="co">// S&lt;int&gt; is now defined to the equivalent of</span></span>
<span id="cb68-22"><a href="#cb68-22"></a><span class="co">// template&lt;&gt; struct S&lt;int&gt; {</span></span>
<span id="cb68-23"><a href="#cb68-23"></a><span class="co">//   alignas(64) int i;</span></span>
<span id="cb68-24"><a href="#cb68-24"></a><span class="co">//   alignas(64) int j;</span></span>
<span id="cb68-25"><a href="#cb68-25"></a><span class="co">// };</span></span></code></pre></div>
</blockquote>
<p>When defining a <code class="sourceCode cpp"><span class="kw">union</span></code>, if one of the alternatives has a non-trivial destructor, the defined union will <em>still</em> have a destructor provided - that simply does nothing. This allows implementing <a href="#a-simple-variant-type">variant</a> without having to further extend support in <code class="sourceCode cpp">define_class</code> for member functions.</p>
<h3 data-number="4.4.16" id="data-layout-reflection"><span class="header-section-number">4.4.16</span> Data Layout Reflection<a href="#data-layout-reflection" class="self-link"></a></h3>
<blockquote>
<div class="sourceCode" id="cb69"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb69-1"><a href="#cb69-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb69-2"><a href="#cb69-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="cb69-3"><a href="#cb69-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="cb69-4"><a href="#cb69-4"></a></span>
<span id="cb69-5"><a href="#cb69-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="cb69-6"><a href="#cb69-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="cb69-7"><a href="#cb69-7"></a></span>
<span id="cb69-8"><a href="#cb69-8"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> alignment_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="cb69-9"><a href="#cb69-9"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h3 data-number="4.4.17" id="other-type-traits"><span class="header-section-number">4.4.17</span> Other Type Traits<a href="#other-type-traits" class="self-link"></a></h3>
<p>There is a question of whether all the type traits should be provided in <code class="sourceCode cpp">std<span class="op">::</span>meta</code>. For instance, a few examples in this paper use <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>remove_cvref<span class="op">(</span>t<span class="op">)</span></code> as if that exists. Technically, the functionality isn’t strictly necessary - since it can be provided indirectly:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Direct</strong>
</div></th>
<th><div style="text-align:center">
<strong>Indirect</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb70"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb70-1"><a href="#cb70-1"></a>std<span class="op">::</span>meta<span class="op">::</span>remove_cvref<span class="op">(</span>type<span class="op">)</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb71"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb71-1"><a href="#cb71-1"></a>std<span class="op">::</span>meta<span class="op">::</span>substitute<span class="op">(^</span>std<span class="op">::</span>remove_cvref_t, <span class="op">{</span>type<span class="op">})</span></span></code></pre></div></td>
</tr>
<tr class="even">
<td><div class="sourceCode" id="cb72"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb72-1"><a href="#cb72-1"></a>std<span class="op">::</span>meta<span class="op">::</span>is_const<span class="op">(</span>type<span class="op">)</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb73"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb73-1"><a href="#cb73-1"></a>std<span class="op">::</span>meta<span class="op">::</span>value_of<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>std<span class="op">::</span>meta<span class="op">::</span>substitute<span class="op">(^</span>std<span class="op">::</span>is_const_v, <span class="op">{</span>type<span class="op">}))</span></span>
<span id="cb73-2"><a href="#cb73-2"></a>std<span class="op">::</span>meta<span class="op">::</span>test_type<span class="op">(^</span>std<span class="op">::</span>is_const_v, type<span class="op">)</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>Having <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>meow</code> for every trait <code class="sourceCode cpp">std<span class="op">::</span>meow</code> is more straightforward and will likely be faster to compile, though means we will have a much larger library API. There are quite a few traits in <span>21 <a href="https://wg21.link/meta">[meta]</a></span> - but it should be easy enough to specify all of them. So we’re doing it.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="proposed-wording"><span class="header-section-number">5</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<h2 data-number="5.1" id="language"><span class="header-section-number">5.1</span> Language<a href="#language" class="self-link"></a></h2>
<h3 data-number="5.1.1" id="lex.phases-phases-of-translation"><span class="header-section-number">5.1.1</span> [lex.phases] Phases of translation<a href="#lex.phases-phases-of-translation" class="self-link"></a></h3>
<p>Modify the wording for phases 7-8 of <span>5.2 <a href="https://wg21.link/lex.phases">[lex.phases]</a></span> as follows:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">7</a></span> Whitespace characters separating tokens are no longer significant. Each preprocessing token is converted into a token (5.6). The resulting tokens constitute a translation unit and are syntactically and semantically analyzed and translated. <span class="addu">Plainly constant-evaluated expressions ([expr.const]) appearing outside template declarations are evaluated in lexical order. Diagnosable rules (<span>4.1.1 <a href="https://wg21.link/intro.compliance.general">[intro.compliance.general]</a></span>) that apply to constructs whose syntactic end point occurs lexically after the syntactic end point of a plainly constant-evaluated expression X are considered in a context where X has been evaluated.</span> […]</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">8</a></span> […] All the required instantiations are performed to produce instantiation units. <span class="addu">Plainly constant-evaluated expressions ([expr.const]) appearing in those instantiation units are evaluated in lexical order as part of the instantiation process. Diagnosable rules (<span>4.1.1 <a href="https://wg21.link/intro.compliance.general">[intro.compliance.general]</a></span>) that apply to constructs whose syntactic end point occurs lexically after the syntactic end point of a plainly constant-evaluated expression X are considered in a context where X has been evaluated.</span> […]</p>
</blockquote>
<h3 data-number="5.1.2" id="lex.pptoken-preprocessing-tokens"><span class="header-section-number">5.1.2</span> [lex.pptoken] Preprocessing tokens<a href="#lex.pptoken-preprocessing-tokens" class="self-link"></a></h3>
<p>Add a bullet after <span>5.4 <a href="https://wg21.link/lex.pptoken">[lex.pptoken]</a></span> bullet (3.2):</p>
<blockquote>
<p>…</p>
<p>— Otherwise, if the next three characters are <code class="sourceCode cpp"><span class="op">&lt;::</span></code> and the subsequent character is neither <code class="sourceCode cpp"><span class="op">:</span></code> nor <code class="sourceCode cpp"><span class="op">&gt;</span></code>, the <code class="sourceCode cpp"><span class="op">&lt;</span></code> is treated as a preprocessing token by itself and not as the first character of the alternative token <code class="sourceCode cpp"><span class="op">&lt;:</span></code>.</p>
<div class="addu">
<p>— Otherwise, if the next three characters are <code class="sourceCode cpp"><span class="op">[::</span></code> and the subsequent character is not <code class="sourceCode cpp"><span class="op">:</span></code>, the <code class="sourceCode cpp"><span class="op">[</span></code> is treated as a preprocessing token by itself and not as the first character of the preprocessing token <code class="sourceCode cpp"><span class="op">[:</span></code>.</p>
</div>
<p>…</p>
</blockquote>
<h3 data-number="5.1.3" id="lex.operators-operators-and-punctuators"><span class="header-section-number">5.1.3</span> [lex.operators] Operators and punctuators<a href="#lex.operators-operators-and-punctuators" class="self-link"></a></h3>
<p>Change the grammar for <code class="sourceCode cpp"><em>operator-or-punctuator</em></code> in paragraph 1 of <span>5.12 <a href="https://wg21.link/lex.operators">[lex.operators]</a></span> to include splicer delimiters:</p>
<blockquote>
<div class="sourceCode" id="cb74"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb74-1"><a href="#cb74-1"></a>  <em>operator-or-punctuator</em>: <em>one of</em></span>
<span id="cb74-2"><a href="#cb74-2"></a>         {        }        [        ]        (        )        <span class="addu"><code class="sourceCode cpp"><span class="op">[:</span>        <span class="op">:]</span></code></span></span>
<span id="cb74-3"><a href="#cb74-3"></a>         &lt;:       :&gt;       &lt;%       %&gt;       ;        :        ...</span>
<span id="cb74-4"><a href="#cb74-4"></a>         ?        ::       .       .*        -&gt;       -&gt;*      ~</span>
<span id="cb74-5"><a href="#cb74-5"></a>         !        +        -        *        /        %        ^        &amp;        |</span>
<span id="cb74-6"><a href="#cb74-6"></a>         =        +=       -=       *=       /=       %=       ^=       &amp;=       |=</span>
<span id="cb74-7"><a href="#cb74-7"></a>         ==       !=       &lt;        &gt;        &lt;=       &gt;=       &lt;=&gt;      &amp;&amp;       ||</span>
<span id="cb74-8"><a href="#cb74-8"></a>         &lt;&lt;       &gt;&gt;       &lt;&lt;=      &gt;&gt;=      ++       --       ,</span>
<span id="cb74-9"><a href="#cb74-9"></a>         and      or       xor      not      bitand   bitor    compl</span>
<span id="cb74-10"><a href="#cb74-10"></a>         and_eq   or_eq    xor_eq   not_eq</span></code></pre></div>
</blockquote>
<h3 data-number="5.1.4" id="basic.types.general"><span class="header-section-number">5.1.4</span> [basic.types.general]<a href="#basic.types.general" class="self-link"></a></h3>
<p>Change the first sentence in paragraph 9 of <span>6.8.1 <a href="https://wg21.link/basic.types.general">[basic.types.general]</a></span> as follows:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">9</a></span> Arithmetic types (6.8.2), enumeration types, pointer types, pointer-to-member types (6.8.4),<span class="addu"><code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>,</span> <code class="sourceCode cpp">std<span class="op">::</span>nullptr_t</code>, and cv-qualified (6.8.5) versions of these types are collectively called scalar types.</p>
</blockquote>
<p>Add a new paragraph at the end of <span>6.8.1 <a href="https://wg21.link/basic.types.general">[basic.types.general]</a></span> as follows:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">*</a></span> A <em>consteval-only type</em> is one of the following:</p>
<ul>
<li><code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>, or</li>
<li>a pointer or reference to a consteval-only type, or</li>
<li>an (possibly multi-dimensional) array of a consteval-only type, or</li>
<li>a pointer-to-member type to a class <code class="sourceCode cpp">C</code> of type <code class="sourceCode cpp">M</code> where either <code class="sourceCode cpp">C</code> or <code class="sourceCode cpp">M</code> is a consteval-only type, or</li>
<li>a function type with a consteval-only return type or a consteval-only parameter type, or</li>
<li>a class type with a consteval-only base class type or consteval-only non-static data member type.</li>
</ul>
<p>An object of consteval-only type shall either end its lifetime during the evaluation of a manifestly constant-evaluated expression or conversion (<span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>), or be a constexpr variable that is not odr-used (<span>6.3 <a href="https://wg21.link/basic.def.odr">[basic.def.odr]</a></span>).</p>
</div>
</blockquote>
<h3 data-number="5.1.5" id="basic.fundamental-fundamental-types"><span class="header-section-number">5.1.5</span> [basic.fundamental] Fundamental types<a href="#basic.fundamental-fundamental-types" class="self-link"></a></h3>
<p>Add a new paragraph before the last paragraph of <span>6.8.2 <a href="https://wg21.link/basic.fundamental">[basic.fundamental]</a></span> as follows:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">*</a></span> A value of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> is called a <em>reflection</em> and represents a language element such as a type, a constant value, a non-static data member, etc. An expression convertible to <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> is said to <em>reflect</em> the language element represented by the resulting value; the language element is said to be <em>reflected by</em> the expression. <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code> shall be equal to <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">(</span><span class="dt">void</span><span class="op">*)</span></code>. <span class="note"><span>[ <em>Note 1:</em> </span>Reflections are only meaningful during translation. The notion of consteval-only types (see <span>6.8.1 <a href="https://wg21.link/basic.types.general">[basic.types.general]</a></span>) exists to diagnose attempts at using such values outside the translation process.<span> — <em>end note</em> ]</span></span></p>
</div>
</blockquote>
<h3 data-number="5.1.6" id="basic.lookup.argdep-argument-dependent-name-lookup"><span class="header-section-number">5.1.6</span> [basic.lookup.argdep] Argument-dependent name lookup<a href="#basic.lookup.argdep-argument-dependent-name-lookup" class="self-link"></a></h3>
<p>Add a bullet after the first in paragraph 3 of [basic.lookup.argdep] as follows:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">3</a></span> … Any <code class="sourceCode cpp"><em>typedef-name</em></code>s and <code class="sourceCode cpp"><em>using-declaration</em></code>s used to specify the types do not contribute to this set. The set of entities is determined in the following way:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">(3.1)</a></span> If <code class="sourceCode cpp">T</code> is a fundamental type, its associated set of entities is empty.</li>
</ul>
<div class="addu">
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">(3.2)</a></span> If <code class="sourceCode cpp">T</code> is <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>, its associated set of entities is the singleton containing the function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>is_type</code>.</li>
</ul>
</div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">(3.3)</a></span> If <code class="sourceCode cpp">T</code> is a class type …</li>
</ul>
</blockquote>
<h3 data-number="5.1.7" id="basic.lookup.qual.general-general"><span class="header-section-number">5.1.7</span> [basic.lookup.qual.general] General<a href="#basic.lookup.qual.general-general" class="self-link"></a></h3>
<p>Extend <span>6.5.5.1 <a href="https://wg21.link/basic.lookup.qual.general">[basic.lookup.qual.general]</a></span>/1-2 to cover <code class="sourceCode cpp"><em>splice-name-qualifer</em></code>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">1</a></span> Lookup of an <em>identifier</em> followed by a ​<code class="sourceCode cpp"><span class="op">::</span></code>​ scope resolution operator considers only namespaces, types, and templates whose specializations are types. If a name, <code class="sourceCode cpp"><em>template-id</em></code>, <span class="rm" style="color: #bf0303"><del>or</del></span> <code class="sourceCode cpp"><em>computed-type-specifier</em></code><span class="addu">, or <code class="sourceCode cpp"><em>splice-name-qualifier</em></code></span> is followed by a ​<code class="sourceCode cpp"><span class="op">::</span></code>​, it shall designate a namespace, class, enumeration, or dependent type, and the ​::​ is never interpreted as a complete nested-name-specifier.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">2</a></span> A member-qualified name is the (unique) component name ([expr.prim.id.unqual]), if any, of</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(2.1)</a></span> an <em>unqualified-id</em> or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(2.2)</a></span> a <code class="sourceCode cpp"><em>nested-name-specifier</em></code> of the form <code class="sourceCode cpp"><em>type-name</em> <span class="op">::</span></code> <span class="rm" style="color: #bf0303"><del>or</del></span><span class="addu">,</span> <code class="sourceCode cpp"><em>namespace-name</em> <span class="op">::</span></code><span class="addu">, or <code class="sourceCode cpp"><em>splice-name-qualifier</em> <span class="op">::</span></code></span></li>
</ul>
<p>in the <em>id-expression</em> of a class member access expression ([expr.ref]). […]</p>
</blockquote>
<h3 data-number="5.1.8" id="expr.prim-primary-expressions"><span class="header-section-number">5.1.8</span> [expr.prim] Primary expressions<a href="#expr.prim-primary-expressions" class="self-link"></a></h3>
<p>Change the grammar for <code class="sourceCode cpp"><em>primary-expression</em></code> in <span>7.5 <a href="https://wg21.link/expr.prim">[expr.prim]</a></span> as follows:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb75"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb75-1"><a href="#cb75-1"></a>  <em>primary-expression</em>:</span>
<span id="cb75-2"><a href="#cb75-2"></a>     <em>literal</em></span>
<span id="cb75-3"><a href="#cb75-3"></a>     this</span>
<span id="cb75-4"><a href="#cb75-4"></a>     ( <em>expression</em> )</span>
<span id="cb75-5"><a href="#cb75-5"></a>     <em>id-expression</em></span>
<span id="cb75-6"><a href="#cb75-6"></a>     <em>lambda-expression</em></span>
<span id="cb75-7"><a href="#cb75-7"></a>     <em>fold-expression</em></span>
<span id="cb75-8"><a href="#cb75-8"></a>     <em>requires-expression</em></span>
<span id="cb75-9"><a href="#cb75-9"></a><span class="va">+    [: <em>constant-expression</em> :]</span></span>
<span id="cb75-10"><a href="#cb75-10"></a><span class="va">+    template[: <em>constant-expression</em> :] &lt; <em>template-argument-list</em><sub><em>opt</em></sub> &gt;</span></span></code></pre></div>
</div>
</blockquote>
<h3 data-number="5.1.9" id="expr.prim.id.qual-qualified-names"><span class="header-section-number">5.1.9</span> [expr.prim.id.qual] Qualified names<a href="#expr.prim.id.qual-qualified-names" class="self-link"></a></h3>
<p>Add a production to the grammar for <code class="sourceCode cpp"><em>nested-name-specifier</em></code> as follows:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb76"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb76-1"><a href="#cb76-1"></a>  <em>nested-name-specifier</em>:</span>
<span id="cb76-2"><a href="#cb76-2"></a>      ::</span>
<span id="cb76-3"><a href="#cb76-3"></a>      <em>type-name</em> ::</span>
<span id="cb76-4"><a href="#cb76-4"></a>      <em>namespace-name</em> ::</span>
<span id="cb76-5"><a href="#cb76-5"></a>      <em>computed-type-specifier</em> ::</span>
<span id="cb76-6"><a href="#cb76-6"></a><span class="va">+     <em>splice-name-qualifier</em> ::</span></span>
<span id="cb76-7"><a href="#cb76-7"></a>      <em>nested-name-specifier</em> <em>identifier</em> ::</span>
<span id="cb76-8"><a href="#cb76-8"></a>      <em>nested-name-specifier</em> template<sub><em>opt</em></sub> <em>simple-template-id</em> ::</span>
<span id="cb76-9"><a href="#cb76-9"></a><span class="va">+</span></span>
<span id="cb76-10"><a href="#cb76-10"></a><span class="va">+ <em>splice-name-qualifier</em>:</span></span>
<span id="cb76-11"><a href="#cb76-11"></a><span class="va">+     [: <em>constant-expression</em> :]</span></span></code></pre></div>
</div>
</blockquote>
<p>Extend <span>7.5.4.3 <a href="https://wg21.link/expr.prim.id.qual">[expr.prim.id.qual]</a></span>/1 to also cover splices:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">1</a></span> The component names of a <code class="sourceCode cpp"><em>qualified-id</em></code> are those of its <code class="sourceCode cpp"><em>nested-name-specifier</em></code> and <code class="sourceCode cpp"><em>unqualified-id</em></code>. The component names of a <code class="sourceCode cpp"><em>nested-name-specifier</em></code> are its <code class="sourceCode cpp"><em>identifier</em></code> (if any) and those of its <code class="sourceCode cpp"><em>type-name</em></code>, <code class="sourceCode cpp"><em>namespace-name</em></code>, <code class="sourceCode cpp"><em>simple-template-id</em></code>, <span class="rm" style="color: #bf0303"><del>and/or</del></span> <code class="sourceCode cpp"><em>nested-name-specifier</em></code><span class="addu">, and/or the <code class="sourceCode cpp"><em>type-name</em></code> or <code class="sourceCode cpp"><em>namespace-name</em></code> of the entity reflected by the <code class="sourceCode cpp"><em>constant-expression</em></code> of its <code class="sourceCode cpp"><em>splice-name-qualifier</em></code>. For a <code class="sourceCode cpp"><em>nested-name-specifier</em></code> having a <code class="sourceCode cpp"><em>splice-name-qualifier</em></code> with a <code class="sourceCode cpp"><em>constant-expression</em></code> that reflects the global namespace, the component names are the same as for <code class="sourceCode cpp"><span class="op">::</span></code>. The <code class="sourceCode cpp"><em>constant-expression</em></code> of a <code class="sourceCode cpp"><em>splice-name-qualifier</em></code> shall be a reflection of either a <code class="sourceCode cpp"><em>type-name</em></code>, <code class="sourceCode cpp"><em>namespace-name</em></code>, or the global namespace</span>.</p>
</blockquote>
<p>Extend <span>7.5.4.3 <a href="https://wg21.link/expr.prim.id.qual">[expr.prim.id.qual]</a></span>/3 to also cover splices:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">3</a></span> The <code class="sourceCode cpp"><em>nested-name-specifier</em></code> <code class="sourceCode cpp">​<span class="op">::</span></code>​ nominates the global namespace. A <code class="sourceCode cpp"><em>nested-name-specifier</em></code> with a <code class="sourceCode cpp"><em>computed-type-specifier</em></code> nominates the type denoted by the <code class="sourceCode cpp"><em>computed-type-specifier</em></code>, which shall be a class or enumeration type. <span class="addu">A <code class="sourceCode cpp"><em>nested-name-specifier</em></code> with a <code class="sourceCode cpp"><em>splice-name-qualifier</em></code> nominates the entity reflected by the <code class="sourceCode cpp"><em>constant-expression</em></code> of the <code class="sourceCode cpp"><em>splice-name-qualifier</em></code>.</span> If a nested-name-specifier N is declarative and has a simple-template-id with a template argument list A that involves a template parameter, let T be the template nominated by N without A. T shall be a class template.</p>
<p>…</p>
</blockquote>
<h3 data-number="5.1.10" id="expr.prim.splice-expression-splicing"><span class="header-section-number">5.1.10</span> [expr.prim.splice] Expression splicing<a href="#expr.prim.splice-expression-splicing" class="self-link"></a></h3>
<p>Add a new subsection of <span>7.5 <a href="https://wg21.link/expr.prim">[expr.prim]</a></span> following <span>7.5.7 <a href="https://wg21.link/expr.prim.req">[expr.prim.req]</a></span></p>
<blockquote>
<div class="addu">
<p><strong>Expression Splicing [expr.prim.splice]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">1</a></span> For a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><span class="op">[:</span> <em>constant-expression</em> <span class="op">:]</span></code> or <code class="sourceCode cpp"><span class="kw">template</span><span class="op">[:</span> <em>constant-expression</em> <span class="op">:]</span>  <span class="op">&lt;</span> <em>template-argument-list</em><sub><em>opt</em></sub> <span class="op">&gt;</span></code> the <code class="sourceCode cpp"><em>constant-expression</em></code> shall be a converted constant expression (<span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>) of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">2</a></span> For a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><span class="kw">template</span><span class="op">[:</span> <em>constant-expression</em> <span class="op">:]</span>  <span class="op">&lt;</span> <em>template-argument-list</em><sub><em>opt</em></sub> <span class="op">&gt;</span></code> the converted <code class="sourceCode cpp"><em>constant-expression</em></code> shall evaluate to a reflection for a concept, variable template, class template, alias template, or function template. The meaning of such a construct is identical to that of a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><em>template-name</em> <span class="op">&lt;</span> <em>template-argument-list</em><sub><em>opt</em></sub> <span class="op">&gt;</span></code> where <code class="sourceCode cpp"><em>template-name</em></code> denotes the reflected template or concept (ignoring access checking on the <code class="sourceCode cpp"><em>template-name</em></code>).</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">3</a></span> For a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><span class="op">[:</span> <em>constant-expression</em> <span class="op">:]</span></code> where the converted <code class="sourceCode cpp"><em>constant-expression</em></code> evaluates to a reflection for a variable, a function, an enumerator, or a structured binding, the meaning of the expression is identical to that of a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><em>id-expression</em></code> that would denote the reflected entity (ignoring access checking).</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">4</a></span> Otherwise, for a <code class="sourceCode cpp"><em>primary-expression</em></code> of the form <code class="sourceCode cpp"><span class="op">[:</span> <em>constant-expression</em> <span class="op">:]</span></code> the converted <code class="sourceCode cpp"><em>constant-expression</em></code> shall evaluate to a reflection for a constant value and the expression shall evaluate to that value.</p>
</div>
</blockquote>
<h3 data-number="5.1.11" id="expr.unary.general"><span class="header-section-number">5.1.11</span> [expr.unary.general]<a href="#expr.unary.general" class="self-link"></a></h3>
<p>Change <span>7.6.2.1 <a href="https://wg21.link/expr.unary.general">[expr.unary.general]</a></span> paragraph 1 to add productions for the new operator:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">1</a></span> Expressions with unary operators group right-to-left.</p>
<div>
<div class="sourceCode" id="cb77"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb77-1"><a href="#cb77-1"></a>  <em>unary-expression</em>:</span>
<span id="cb77-2"><a href="#cb77-2"></a>     ...</span>
<span id="cb77-3"><a href="#cb77-3"></a>     <em>delete-expression</em></span>
<span id="cb77-4"><a href="#cb77-4"></a><span class="va">+    ^ ::</span></span>
<span id="cb77-5"><a href="#cb77-5"></a><span class="va">+    ^ <em>namespace-name</em></span></span>
<span id="cb77-6"><a href="#cb77-6"></a><span class="va">+    ^ <em>nested-name-specifier</em><sub><em>opt</em></sub> <em>template-name</em></span></span>
<span id="cb77-7"><a href="#cb77-7"></a><span class="va">+    ^ <em>nested-name-specifier</em><sub><em>opt</em></sub> <em>concept-name</em></span></span>
<span id="cb77-8"><a href="#cb77-8"></a><span class="va">+    ^ <em>type-id</em></span></span>
<span id="cb77-9"><a href="#cb77-9"></a><span class="va">+    ^ <em>cast-expression</em></span></span></code></pre></div>
</div>
</blockquote>
<h3 data-number="5.1.12" id="expr.reflect-the-reflection-operator"><span class="header-section-number">5.1.12</span> [expr.reflect] The reflection operator<a href="#expr.reflect-the-reflection-operator" class="self-link"></a></h3>
<p>Add a new subsection of <span>7.6.2 <a href="https://wg21.link/expr.unary">[expr.unary]</a></span> following <span>7.6.2.9 <a href="https://wg21.link/expr.delete">[expr.delete]</a></span></p>
<blockquote>
<div class="addu">
<p><strong>The Reflection Operator [expr.reflect]</strong></p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">1</a></span> The unary <code class="sourceCode cpp"><span class="op">^</span></code> operator (called <em>the reflection operator</em>) produces a prvalue — called <em>reflection</em> — whose type is the reflection type (i.e., <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>). That reflection represents its operand.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">2</a></span> An ambiguity can arise between the interpretation of the operand of the reflection operator as a <code class="sourceCode cpp"><em>type-id</em></code> or a <code class="sourceCode cpp"><em>cast-expression</em></code>; in such cases, the <code class="sourceCode cpp"><em>type-id</em></code> treatment is chosen. Parentheses can be introduced to force the <code class="sourceCode cpp"><em>cast-expression</em></code> interpretation.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">3</a></span> [<em>Example</em></p>
<div class="sourceCode" id="cb78"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb78-1"><a href="#cb78-1"></a>static_assert(is_type(^int()));    // ^ applies to the type-id &quot;int()&quot;; not the cast &quot;int()&quot;</span>
<span id="cb78-2"><a href="#cb78-2"></a>static_assert(!is_type(^(int()))); // ^ applies to the the cast-expression &quot;(int())&quot;</span>
<span id="cb78-3"><a href="#cb78-3"></a></span>
<span id="cb78-4"><a href="#cb78-4"></a>template&lt;bool&gt; struct X;</span>
<span id="cb78-5"><a href="#cb78-5"></a>consteval void g(std::meta::info r) {</span>
<span id="cb78-6"><a href="#cb78-6"></a>  if (r == ^int &amp;&amp; true);    // error: ^ applies to the type-id &quot;int&amp;&amp;&quot;</span>
<span id="cb78-7"><a href="#cb78-7"></a>  if (r == (^int) &amp;&amp; true);  // OK</span>
<span id="cb78-8"><a href="#cb78-8"></a>  if (r == ^X &lt; true);       // error: &quot;&lt;&quot; is an angle bracket</span>
<span id="cb78-9"><a href="#cb78-9"></a>  if (r == (^X) &lt; true);     // OK</span>
<span id="cb78-10"><a href="#cb78-10"></a>}</span>
<span id="cb78-11"><a href="#cb78-11"></a></span></code></pre></div>
<p>-<em>end example</em>]</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">4</a></span> When applied to <code class="sourceCode cpp"><span class="op">::</span></code>, the reflection operator produces a reflection for the global namespace. When applied to a <code class="sourceCode cpp"><em>namespace-name</em></code>, the reflection produces a reflection for the indicated namespace or namespace alias.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">5</a></span> When applied to a <code class="sourceCode cpp"><em>template-name</em></code>, the reflection produces a reflection for the indicated template.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">6</a></span> When applied to a <code class="sourceCode cpp"><em>concept-name</em></code>, the reflection produces a reflection for the indicated concept.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">7</a></span> When applied to a <code class="sourceCode cpp"><em>type-id</em></code>, the reflection produces a reflection for the indicated type or type alias.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_28" id="pnum_28">8</a></span> When applied to a <code class="sourceCode cpp"><em>cast-expression</em></code>, the <code class="sourceCode cpp"><em>cast-expression</em></code> shall be a constant expression (<span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>) or an <code class="sourceCode cpp"><em>id-expression</em></code> (<span>7.5.4 <a href="https://wg21.link/expr.prim.id">[expr.prim.id]</a></span>) designating a variable, a function, an enumerator constant, or a nonstatic member. The <code class="sourceCode cpp"><em>cast-expression</em></code> is not evaluated.</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_29" id="pnum_29">(8.1)</a></span> If the operand of the reflection operator is an <code class="sourceCode cpp"><em>id-expression</em></code>, the result is a reflection for the indicated entity.</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_30" id="pnum_30">(8.1.1)</a></span> If this <code class="sourceCode cpp"><em>id-expression</em></code> names an overload set <code class="sourceCode cpp">S</code>, and if the assignment of <code class="sourceCode cpp">S</code> to an invented variable of type <code class="sourceCode cpp"><span class="kw">const</span> <span class="kw">auto</span></code> (<span>9.2.9.6.2 <a href="https://wg21.link/dcl.type.auto.deduct">[dcl.type.auto.deduct]</a></span>) would select a unique candidate function <code class="sourceCode cpp">F</code> from <code class="sourceCode cpp">S</code>, the result is a reflection of <code class="sourceCode cpp">F</code>. Otherwise, the expression <code class="sourceCode cpp"><span class="op">^</span>S</code> is ill-formed.</li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_31" id="pnum_31">(8.2)</a></span> If the operand is a constant expression, the result is a reflection for the resulting value.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_32" id="pnum_32">(8.3)</a></span> If the operand is both an <code class="sourceCode cpp"><em>id-expression</em></code> and a constant expression, the result is a reflection for both the indicated entity and the expression’s (constant) value.</p></li>
</ul>
<p>[ <em>Example</em>:</p>
<div class="sourceCode" id="cb79"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb79-1"><a href="#cb79-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="dt">void</span> fn<span class="op">()</span> <span class="kw">requires</span> <span class="op">(^</span>T <span class="op">!=</span> <span class="op">^</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb79-2"><a href="#cb79-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="dt">void</span> fn<span class="op">()</span> <span class="kw">requires</span> <span class="op">(^</span>T <span class="op">==</span> <span class="op">^</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb79-3"><a href="#cb79-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="dt">void</span> fn<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>T<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">)</span>;</span>
<span id="cb79-4"><a href="#cb79-4"></a></span>
<span id="cb79-5"><a href="#cb79-5"></a><span class="kw">constexpr</span> <span class="kw">auto</span> R <span class="op">=</span> <span class="op">^</span>fn<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span>;     <span class="co">// OK</span></span>
<span id="cb79-6"><a href="#cb79-6"></a><span class="kw">constexpr</span> <span class="kw">auto</span> S <span class="op">=</span> <span class="op">^</span>fn<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>;      <span class="co">// error: cannot reflect an overload set</span></span>
<span id="cb79-7"><a href="#cb79-7"></a></span>
<span id="cb79-8"><a href="#cb79-8"></a><span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> <span class="op">^</span>std<span class="op">::</span>vector;  <span class="co">// OK</span></span></code></pre></div>
<p>— <em>end example</em> ]</p>
</div>
</blockquote>
<h3 data-number="5.1.13" id="expr.eq-equality-operators"><span class="header-section-number">5.1.13</span> [expr.eq] Equality Operators<a href="#expr.eq-equality-operators" class="self-link"></a></h3>
<p>Extend <span>7.6.10 <a href="https://wg21.link/expr.eq">[expr.eq]</a></span>/2 to also handle `std::meta::info:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_33" id="pnum_33">2</a></span> The converted operands shall have arithmetic, enumeration, pointer, or pointer-to-member type, or <span class="rm" style="color: #bf0303"><del>type</del></span> <span class="addu">types <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> or</span> <code class="sourceCode cpp">std​<span class="op">::</span>​nullptr_t</code>. The operators <code class="sourceCode cpp"><span class="op">==</span></code> and <code class="sourceCode cpp"><span class="op">!=</span></code> both yield <code class="sourceCode cpp"><span class="kw">true</span></code> or <code class="sourceCode cpp"><span class="kw">false</span></code>, i.e., a result of type <code class="sourceCode cpp"><span class="dt">bool</span></code>. In each case below, the operands shall have the same type after the specified conversions have been applied.</p>
</blockquote>
<p>Add a new paragraph between <span>7.6.10 <a href="https://wg21.link/expr.eq">[expr.eq]</a></span>/5 and /6:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_34" id="pnum_34">5</a></span> Two operands of type <code class="sourceCode cpp">std​<span class="op">::</span>​nullptr_t</code> or one operand of type <code class="sourceCode cpp">std​<span class="op">::</span>​nullptr_t</code> and the other a null pointer constant compare equal.</p>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_35" id="pnum_35">*</a></span> If both operands are of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>, comparison is defined as follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_36" id="pnum_36">(*.1)</a></span> If one operand is a reflection of a namespace alias, alias template, or type alias and the other operand is not a reflection of the same kind of alias, they compare unequal. <span class="note"><span>[ <em>Note 1:</em> </span>A reflection of a type and a reflection of an alias to that same type do not compare equal.<span> — <em>end note</em> ]</span></span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_37" id="pnum_37">(*.2)</a></span> Otherwise, if both operands are reflections of a namespace alias, alias template, or type alias, then they compare equal if they are reflections of the same namespace alias, alias template, or type alias, respectively.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_38" id="pnum_38">(*.3)</a></span> Otherwise, if neither operand is a reflection of an expression, then they compare equal if they are reflections of the same entity.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_39" id="pnum_39">(*.4)</a></span> Otherwise, if one operand is a reflection of an expression and the other is not, then they compare unequal.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_40" id="pnum_40">(*.5)</a></span> Otherwise (if both operands are reflections of expressions):
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_41" id="pnum_41">(*.5.1)</a></span> If both operands designate <em>id-expressions</em>, then they compare equal if they identify the same declared entity.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_42" id="pnum_42">(*.5.2)</a></span> Otherwise, if one operand designates an <em>id-expression</em>, then they compare unequal.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_43" id="pnum_43">(*.5.3)</a></span> Otherwise, the result is unspecified.</li>
</ul></li>
</ul>
</div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_44" id="pnum_44">6</a></span> If two operands compare equal, the result is <code class="sourceCode cpp"><span class="kw">true</span></code> for the <code class="sourceCode cpp"><span class="op">==</span></code> operator and <code class="sourceCode cpp"><span class="kw">false</span></code> for the <code class="sourceCode cpp"><span class="op">!=</span></code> operator. If two operands compare unequal, the result is <code class="sourceCode cpp"><span class="kw">false</span></code> for the <code class="sourceCode cpp"><span class="op">==</span></code> operator and <code class="sourceCode cpp"><span class="kw">true</span></code> for the <code class="sourceCode cpp"><span class="op">!=</span></code> operator. Otherwise, the result of each of the operators is unspecified.</p>
</blockquote>
<h3 data-number="5.1.14" id="expr.const-constant-expressions"><span class="header-section-number">5.1.14</span> [expr.const] Constant Expressions<a href="#expr.const-constant-expressions" class="self-link"></a></h3>
<p>Add a new paragraph after the definition of <em>manifestly constant-evaluated</em> <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/20:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_45" id="pnum_45">21</a></span> An expression or conversion is <em>plainly constant-evaluated</em> if it is:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_46" id="pnum_46">(21.1)</a></span> a <code class="sourceCode cpp"><em>constant-expression</em></code>, or</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_47" id="pnum_47">(21.2)</a></span> the condition of a constexpr if statement (<span>8.5.2 <a href="https://wg21.link/stmt.if">[stmt.if]</a></span>),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_48" id="pnum_48">(21.3)</a></span> the initializer of a <code class="sourceCode cpp"><span class="kw">constexpr</span></code> (<span>9.2.6 <a href="https://wg21.link/dcl.constexpr">[dcl.constexpr]</a></span>) or <code class="sourceCode cpp"><span class="kw">constinit</span></code> (<span>9.2.7 <a href="https://wg21.link/dcl.constinit">[dcl.constinit]</a></span>) variable, or</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_49" id="pnum_49">(21.4)</a></span> an immediate invocation, unless it</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_50" id="pnum_50">(21.4.1)</a></span> results from the substitution of template parameters in a concept-id (<span>13.3 <a href="https://wg21.link/temp.names">[temp.names]</a></span>), a <code class="sourceCode cpp"><em>requires-expression</em></code> (<span>7.5.7 <a href="https://wg21.link/expr.prim.req">[expr.prim.req]</a></span>), or during template argument deduction (<span>13.10.3 <a href="https://wg21.link/temp.deduct">[temp.deduct]</a></span>), or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_51" id="pnum_51">(21.4.2)</a></span> is a manifestly constant-evaluated initializer of a variable that is neither <code class="sourceCode cpp"><span class="kw">constexpr</span></code> (<span>9.2.6 <a href="https://wg21.link/dcl.constexpr">[dcl.constexpr]</a></span>) nor <code class="sourceCode cpp"><span class="kw">constinit</span></code> (<span>9.2.7 <a href="https://wg21.link/dcl.constinit">[dcl.constinit]</a></span>).</li>
</ul></li>
</ul>
</div>
</blockquote>
<h3 data-number="5.1.15" id="dcl.typedef-the-typedef-specifier"><span class="header-section-number">5.1.15</span> [dcl.typedef] The <code class="sourceCode cpp"><span class="kw">typedef</span></code> specifier<a href="#dcl.typedef-the-typedef-specifier" class="self-link"></a></h3>
<p>Introduce the term “type alias” to <span>9.2.4 <a href="https://wg21.link/dcl.typedef">[dcl.typedef]</a></span>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_52" id="pnum_52">1</a></span> […] A name declared with the <code class="sourceCode cpp"><span class="kw">typedef</span></code> specifier becomes a typedef-name. A typedef-name names the type associated with the identifier ([dcl.decl]) or simple-template-id ([temp.pre]); a typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration ([class.name]) or enum declaration ([dcl.enum]) does.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_53" id="pnum_53">2</a></span> A <em>typedef-name</em> can also be introduced by an alias-declaration. The identifier following the using keyword is not looked up; it becomes a typedef-name and the optional attribute-specifier-seq following the identifier appertains to that typedef-name. Such a typedef-name has the same semantics as if it were introduced by the typedef specifier. In particular, it does not define a new type.</p>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_54" id="pnum_54">*</a></span> A <em>type alias</em> is either a name declared with the <code class="sourceCode cpp"><span class="kw">typedef</span></code> specifier or a name introduced by an <em>alias-declaration</em>.</p>
</div>
</blockquote>
<h3 data-number="5.1.16" id="dcl.attr.grammar-attribute-syntax-and-semantics"><span class="header-section-number">5.1.16</span> [dcl.attr.grammar] Attribute syntax and semantics<a href="#dcl.attr.grammar-attribute-syntax-and-semantics" class="self-link"></a></h3>
<p>Add a production to the grammar for <code class="sourceCode cpp"><em>attribute-specifier</em></code> as follows:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb80"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb80-1"><a href="#cb80-1"></a>  <em>attribute-specifier</em>:</span>
<span id="cb80-2"><a href="#cb80-2"></a>     [ [ <em>attribute-using-prefix</em><sub><em>opt</em></sub> <em>attribute-list</em> ] ]</span>
<span id="cb80-3"><a href="#cb80-3"></a><span class="va">+    [ [ using <em>attribute-namespace</em> :] ]</span></span>
<span id="cb80-4"><a href="#cb80-4"></a>     <em>alignment-specifier</em></span></code></pre></div>
</div>
</blockquote>
<p>and update the grammar for balanced token as follows:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb81"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb81-1"><a href="#cb81-1"></a>  <em>balanced-token</em> :</span>
<span id="cb81-2"><a href="#cb81-2"></a>      ( <em>balanced-token-seq</em><sub><em>opt</em></sub> )</span>
<span id="cb81-3"><a href="#cb81-3"></a>      [ <em>balanced-token-seq</em><sub><em>opt</em></sub> ]</span>
<span id="cb81-4"><a href="#cb81-4"></a>      { <em>balanced-token-seq</em><sub><em>opt</em></sub> }</span>
<span id="cb81-5"><a href="#cb81-5"></a><span class="st">-     any token other than a parenthesis, a bracket, or a brace</span></span>
<span id="cb81-6"><a href="#cb81-6"></a><span class="va">+     [: <em>balanced-token-seq</em><sub><em>opt</em></sub> :]</span></span>
<span id="cb81-7"><a href="#cb81-7"></a><span class="va">+     any token other than (, ), [, ], {, }, [:, or :]</span></span></code></pre></div>
</div>
</blockquote>
<p>Change a sentence in paragraph 4 of <span>9.12.1 <a href="https://wg21.link/dcl.attr.grammar">[dcl.attr.grammar]</a></span> as follows:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_55" id="pnum_55">4</a></span> […] An <code class="sourceCode cpp"><em>attribute-specifier</em></code> that contains no <code class="sourceCode cpp"><em>attribute</em></code>s <span class="addu">and no <code class="sourceCode cpp"><em>alignment-specifier</em></code></span> has no effect. <span class="addu"><span class="note"><span>[ <em>Note 1:</em> </span>That includes an <code class="sourceCode cpp"><em>attribute-specifier</em></code> of the form <code class="sourceCode cpp"><span class="op">[</span> <span class="op">[</span> <span class="kw">using</span> <em>attribute-namespace</em> <span class="op">:]</span> <span class="op">]</span></code> which is thus equivalent to replacing the <code class="sourceCode cpp"><span class="op">:]</span></code> token by the two-token sequence <code class="sourceCode cpp"><span class="op">:</span></code> <code class="sourceCode cpp"><span class="op">]</span></code>.<span> — <em>end note</em> ]</span></span></span> …</p>
</blockquote>
<h3 data-number="5.1.17" id="temp.names-names-of-template-specializations"><span class="header-section-number">5.1.17</span> [temp.names] Names of template specializations<a href="#temp.names-names-of-template-specializations" class="self-link"></a></h3>
<p>Modify the grammar for <code class="sourceCode cpp"><em>template-argument</em></code> as follows:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb82"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb82-1"><a href="#cb82-1"></a><span class="va">+ <em>splice-template-argument</em>:</span></span>
<span id="cb82-2"><a href="#cb82-2"></a><span class="va">+     [: constant-expression :]</span></span>
<span id="cb82-3"><a href="#cb82-3"></a><span class="va">+</span></span>
<span id="cb82-4"><a href="#cb82-4"></a>  <em>template-argument</em>:</span>
<span id="cb82-5"><a href="#cb82-5"></a>      <em>constant-expression</em></span>
<span id="cb82-6"><a href="#cb82-6"></a>      <em>type-id</em></span>
<span id="cb82-7"><a href="#cb82-7"></a>      <em>id-expression</em></span>
<span id="cb82-8"><a href="#cb82-8"></a>      <em>braced-init-list</em></span>
<span id="cb82-9"><a href="#cb82-9"></a><span class="va">+     <em>splice-template-argument</em></span></span></code></pre></div>
</div>
</blockquote>
<h3 data-number="5.1.18" id="temp.arg.general-general"><span class="header-section-number">5.1.18</span> [temp.arg.general] General<a href="#temp.arg.general-general" class="self-link"></a></h3>
<p>Adjust paragraph 3 of [temp.arg.general] to not apply to splice template arguments:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_56" id="pnum_56">3</a></span> In a <code class="sourceCode cpp"><em>template-argument</em></code> <span class="addu">which does not contain a <code class="sourceCode cpp"><em>splice-template-argument</em></code></span>, an ambiguity between a <code class="sourceCode cpp"><em>type-id</em></code> and an expression is resolved to a <code class="sourceCode cpp"><em>type-id</em></code>, regardless of the form of the corresponding <code class="sourceCode cpp"><em>template-parameter</em></code>. <span class="addu">In a <code class="sourceCode cpp"><em>template-argument</em></code> containing a <code class="sourceCode cpp"><em>splice-template-argument</em></code>, an ambiguity between a <code class="sourceCode cpp"><em>splice-template-argument</em></code> and an expression is resolved to a <code class="sourceCode cpp"><em>splice-template-argument</em></code>.</span></p>
</blockquote>
<h3 data-number="5.1.19" id="temp.arg.type-template-type-arguments"><span class="header-section-number">5.1.19</span> [temp.arg.type] Template type arguments<a href="#temp.arg.type-template-type-arguments" class="self-link"></a></h3>
<p>Extend <span>13.4.2 <a href="https://wg21.link/temp.arg.type">[temp.arg.type]</a></span>/1 to cover splice template arguments:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_57" id="pnum_57">1</a></span> A <code class="sourceCode cpp"><em>template-argument</em></code> for a <code class="sourceCode cpp"><em>template-parameter</em></code> which is a type shall <span class="addu">either</span> be a <code class="sourceCode cpp"><em>type-id</em></code> <span class="addu">or a <code class="sourceCode cpp"><em>splice-template-argument</em></code>. A <code class="sourceCode cpp"><em>template-argument</em></code> having a <code class="sourceCode cpp"><em>splice-template-argument</em></code> for such a <code class="sourceCode cpp"><em>template-parameter</em></code> is treated as if were a <code class="sourceCode cpp"><em>type-id</em></code> nominating the type reflected by the <code class="sourceCode cpp"><em>constant-expression</em></code> of the <code class="sourceCode cpp"><em>splice-template-argument</em></code>.</span></p>
</blockquote>
<h3 data-number="5.1.20" id="temp.arg.nontype-template-non-type-arguments"><span class="header-section-number">5.1.20</span> [temp.arg.nontype] Template non-type arguments<a href="#temp.arg.nontype-template-non-type-arguments" class="self-link"></a></h3>
<p>Extend <span>13.4.3 <a href="https://wg21.link/temp.arg.nontype">[temp.arg.nontype]</a></span>/2 to cover splice template arguments:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_58" id="pnum_58">2</a></span> The value of a non-type <code class="sourceCode cpp"><em>template-parameter</em></code> <em>P</em> of (possibly deduced) type <code class="sourceCode cpp">T</code> is determined from its template argument <em>A</em> as follows. If <code class="sourceCode cpp">T</code> is not a class type and <em>A</em> is <span class="rm" style="color: #bf0303"><del>not</del></span><span class="addu">neither</span> a <code class="sourceCode cpp"><em>braced-init-list</em></code> <span class="addu">nor a <code class="sourceCode cpp"><em>splice-template-argument</em></code></span>, <em>A</em> shall be a converted constant expression ([expr.const]) of type <code class="sourceCode cpp">T</code>; the value of <em>P</em> is <em>A</em> (as converted).</p>
</blockquote>
<h3 data-number="5.1.21" id="temp.arg.template-template-template-arguments"><span class="header-section-number">5.1.21</span> [temp.arg.template] Template template arguments<a href="#temp.arg.template-template-template-arguments" class="self-link"></a></h3>
<p>Extend <span>13.4.4 <a href="https://wg21.link/temp.arg.template">[temp.arg.template]</a></span>/1 to cover splice template arguments:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_59" id="pnum_59">1</a></span> A <code class="sourceCode cpp"><em>template-argument</em></code> for a template <code class="sourceCode cpp"><em>template-parameter</em></code> shall be the name of a class template or an alias template, expressed as <code class="sourceCode cpp"><em>id-expression</em></code><span class="addu">, or a <code class="sourceCode cpp"><em>splice-template-argument</em></code>. A <code class="sourceCode cpp"><em>template-argument</em></code> for a template <code class="sourceCode cpp"><em>template-parameter</em></code> having a <code class="sourceCode cpp"><em>splice-template-argument</em></code> is treated as an <code class="sourceCode cpp"><em>id-expression</em></code> nominating the class template or alias template reflected by the <code class="sourceCode cpp"><em>constant-expression</em></code> of the <code class="sourceCode cpp"><em>splice-template-argument</em></code>.</span></p>
</blockquote>
<h2 data-number="5.2" id="library"><span class="header-section-number">5.2</span> Library<a href="#library" class="self-link"></a></h2>
<h3 data-number="5.2.1" id="over.built-built-in-operators"><span class="header-section-number">5.2.1</span> [over.built] Built-in operators<a href="#over.built-built-in-operators" class="self-link"></a></h3>
<p>Add built-in operator candidates for <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code> to <span>12.5 <a href="https://wg21.link/over.built">[over.built]</a></span>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_60" id="pnum_60">16</a></span> For every <code class="sourceCode cpp">T</code>, where <code class="sourceCode cpp">T</code> is a pointer-to-member type<span class="addu">, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>,</span> or <code class="sourceCode cpp">std​<span class="op">::</span>​nullptr_t</code>, there exist candidate operator functions of the form</p>
<div class="sourceCode" id="cb83"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb83-1"><a href="#cb83-1"></a><span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>T, T<span class="op">)</span>;</span>
<span id="cb83-2"><a href="#cb83-2"></a><span class="dt">bool</span> <span class="kw">operator</span><span class="op">!=(</span>T, T<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<h3 data-number="5.2.2" id="header-meta-synopsis"><span class="header-section-number">5.2.2</span> Header <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code> synopsis<a href="#header-meta-synopsis" class="self-link"></a></h3>
<p>Add a new subsection in <span>21 <a href="https://wg21.link/meta">[meta]</a></span> after <span>21.3 <a href="https://wg21.link/type.traits">[type.traits]</a></span>:</p>
<blockquote>
<div class="addu">
<p><strong>Header <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code> synopsis</strong></p>
<div class="sourceCode" id="cb84"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb84-1"><a href="#cb84-1"></a>namespace std::meta {</span>
<span id="cb84-2"><a href="#cb84-2"></a>  using info = decltype(^::);</span>
<span id="cb84-3"><a href="#cb84-3"></a></span>
<span id="cb84-4"><a href="#cb84-4"></a>  // [meta.reflection.names], reflection names and locations</span>
<span id="cb84-5"><a href="#cb84-5"></a>  consteval string_view name_of(info r);</span>
<span id="cb84-6"><a href="#cb84-6"></a>  consteval string_view qualified_name_of(info r);</span>
<span id="cb84-7"><a href="#cb84-7"></a>  consteval string_view display_name_of(info r);</span>
<span id="cb84-8"><a href="#cb84-8"></a>  consteval source_location source_location_of(info r);</span>
<span id="cb84-9"><a href="#cb84-9"></a></span>
<span id="cb84-10"><a href="#cb84-10"></a>  // [meta.reflection.queries], reflection queries</span>
<span id="cb84-11"><a href="#cb84-11"></a>  consteval bool is_public(info r);</span>
<span id="cb84-12"><a href="#cb84-12"></a>  consteval bool is_protected(info r);</span>
<span id="cb84-13"><a href="#cb84-13"></a>  consteval bool is_private(info r);</span>
<span id="cb84-14"><a href="#cb84-14"></a>  consteval bool is_accessible(info r);</span>
<span id="cb84-15"><a href="#cb84-15"></a>  consteval bool is_virtual(info r);</span>
<span id="cb84-16"><a href="#cb84-16"></a>  consteval bool is_pure_virtual(info r);</span>
<span id="cb84-17"><a href="#cb84-17"></a>  consteval bool is_override(info r);</span>
<span id="cb84-18"><a href="#cb84-18"></a>  consteval bool is_deleted(info r);</span>
<span id="cb84-19"><a href="#cb84-19"></a>  consteval bool is_defaulted(info r);</span>
<span id="cb84-20"><a href="#cb84-20"></a>  consteval bool is_explicit(info r);</span>
<span id="cb84-21"><a href="#cb84-21"></a>  consteval bool is_bit_field(info r);</span>
<span id="cb84-22"><a href="#cb84-22"></a>  consteval bool has_static_storage_duration(info r);</span>
<span id="cb84-23"><a href="#cb84-23"></a>  consteval bool has_internal_linkage(info r);</span>
<span id="cb84-24"><a href="#cb84-24"></a>  consteval bool has_external_linkage(info r);</span>
<span id="cb84-25"><a href="#cb84-25"></a>  consteval bool has_linkage(info r);</span>
<span id="cb84-26"><a href="#cb84-26"></a></span>
<span id="cb84-27"><a href="#cb84-27"></a>  consteval bool is_namespace(info r);</span>
<span id="cb84-28"><a href="#cb84-28"></a>  consteval bool is_function(info r);</span>
<span id="cb84-29"><a href="#cb84-29"></a>  consteval bool is_variable(info r);</span>
<span id="cb84-30"><a href="#cb84-30"></a>  consteval bool is_type(info r);</span>
<span id="cb84-31"><a href="#cb84-31"></a>  consteval bool is_alias(info r);</span>
<span id="cb84-32"><a href="#cb84-32"></a>  consteval bool is_incomplete_type(info r);</span>
<span id="cb84-33"><a href="#cb84-33"></a>  consteval bool is_template(info r);</span>
<span id="cb84-34"><a href="#cb84-34"></a>  consteval bool is_function_template(info r);</span>
<span id="cb84-35"><a href="#cb84-35"></a>  consteval bool is_variable_template(info r);</span>
<span id="cb84-36"><a href="#cb84-36"></a>  consteval bool is_class_template(info r);</span>
<span id="cb84-37"><a href="#cb84-37"></a>  consteval bool is_alias_template(info r);</span>
<span id="cb84-38"><a href="#cb84-38"></a>  consteval bool is_concept(info r);</span>
<span id="cb84-39"><a href="#cb84-39"></a>  consteval bool has_template_arguments(info r);</span>
<span id="cb84-40"><a href="#cb84-40"></a>  consteval auto is_class_member(info entity) -&gt; bool;</span>
<span id="cb84-41"><a href="#cb84-41"></a>  consteval auto is_namespace_member(info entity) -&gt; bool;</span>
<span id="cb84-42"><a href="#cb84-42"></a>  consteval bool is_nonstatic_data_member(info r);</span>
<span id="cb84-43"><a href="#cb84-43"></a>  consteval bool is_static_member(info r);</span>
<span id="cb84-44"><a href="#cb84-44"></a>  consteval bool is_base(info r);</span>
<span id="cb84-45"><a href="#cb84-45"></a>  consteval bool is_constructor(info r);</span>
<span id="cb84-46"><a href="#cb84-46"></a>  consteval bool is_destructor(info r);</span>
<span id="cb84-47"><a href="#cb84-47"></a>  consteval bool is_special_member(info r);</span>
<span id="cb84-48"><a href="#cb84-48"></a></span>
<span id="cb84-49"><a href="#cb84-49"></a>  consteval info type_of(info r);</span>
<span id="cb84-50"><a href="#cb84-50"></a>  consteval info parent_of(info r);</span>
<span id="cb84-51"><a href="#cb84-51"></a>  consteval info dealias(info r);</span>
<span id="cb84-52"><a href="#cb84-52"></a>  consteval info template_of(info r);</span>
<span id="cb84-53"><a href="#cb84-53"></a>  consteval vector&lt;info&gt; template_arguments_of(info r);</span>
<span id="cb84-54"><a href="#cb84-54"></a></span>
<span id="cb84-55"><a href="#cb84-55"></a>  // [meta.reflection.member.queries], reflection member queries</span>
<span id="cb84-56"><a href="#cb84-56"></a>  template&lt;class... Fs&gt;</span>
<span id="cb84-57"><a href="#cb84-57"></a>    consteval vector&lt;info&gt; members_of(info type, Fs... filters);</span>
<span id="cb84-58"><a href="#cb84-58"></a>  template&lt;class... Fs&gt;</span>
<span id="cb84-59"><a href="#cb84-59"></a>    consteval vector&lt;info&gt; bases_of(info type, Fs... filters);</span>
<span id="cb84-60"><a href="#cb84-60"></a>  consteval vector&lt;info&gt; static_data_members_of(info type);</span>
<span id="cb84-61"><a href="#cb84-61"></a>  consteval vector&lt;info&gt; nonstatic_data_members_of(info type);</span>
<span id="cb84-62"><a href="#cb84-62"></a>  consteval vector&lt;info&gt; subobjects_of(info type);</span>
<span id="cb84-63"><a href="#cb84-63"></a>  consteval vector&lt;info&gt; enumerators_of(info enum_type);</span>
<span id="cb84-64"><a href="#cb84-64"></a></span>
<span id="cb84-65"><a href="#cb84-65"></a>  // [meta.reflection.unary.cat], primary type categories</span>
<span id="cb84-66"><a href="#cb84-66"></a>  consteval bool is_void(info type);</span>
<span id="cb84-67"><a href="#cb84-67"></a>  consteval bool is_null_pointer(info type);</span>
<span id="cb84-68"><a href="#cb84-68"></a>  consteval bool is_integral(info type);</span>
<span id="cb84-69"><a href="#cb84-69"></a>  consteval bool is_floating_point(info type);</span>
<span id="cb84-70"><a href="#cb84-70"></a>  consteval bool is_array(info type);</span>
<span id="cb84-71"><a href="#cb84-71"></a>  consteval bool is_pointer(info type);</span>
<span id="cb84-72"><a href="#cb84-72"></a>  consteval bool is_lvalue_reference(info type);</span>
<span id="cb84-73"><a href="#cb84-73"></a>  consteval bool is_rvalue_reference(info type);</span>
<span id="cb84-74"><a href="#cb84-74"></a>  consteval bool is_member_object_pointer(info type);</span>
<span id="cb84-75"><a href="#cb84-75"></a>  consteval bool is_member_function_pointer(info type);</span>
<span id="cb84-76"><a href="#cb84-76"></a>  consteval bool is_enum(info type);</span>
<span id="cb84-77"><a href="#cb84-77"></a>  consteval bool is_union(info type);</span>
<span id="cb84-78"><a href="#cb84-78"></a>  consteval bool is_class(info type);</span>
<span id="cb84-79"><a href="#cb84-79"></a>  consteval bool is_function(info type);</span>
<span id="cb84-80"><a href="#cb84-80"></a></span>
<span id="cb84-81"><a href="#cb84-81"></a>  // [meta.reflection.unary.comp], composite type categories</span>
<span id="cb84-82"><a href="#cb84-82"></a>  consteval bool is_reference(info type);</span>
<span id="cb84-83"><a href="#cb84-83"></a>  consteval bool is_arithmetic(info type);</span>
<span id="cb84-84"><a href="#cb84-84"></a>  consteval bool is_fundamental(info type);</span>
<span id="cb84-85"><a href="#cb84-85"></a>  consteval bool is_object(info type);</span>
<span id="cb84-86"><a href="#cb84-86"></a>  consteval bool is_scalar(info type);</span>
<span id="cb84-87"><a href="#cb84-87"></a>  consteval bool is_compound(info type);</span>
<span id="cb84-88"><a href="#cb84-88"></a>  consteval bool is_member_pointer(info type);</span>
<span id="cb84-89"><a href="#cb84-89"></a></span>
<span id="cb84-90"><a href="#cb84-90"></a>  // [meta.reflection unary.prop], type properties</span>
<span id="cb84-91"><a href="#cb84-91"></a>  consteval bool is_const(info type);</span>
<span id="cb84-92"><a href="#cb84-92"></a>  consteval bool is_volatile(info type);</span>
<span id="cb84-93"><a href="#cb84-93"></a>  consteval bool is_trivial(info type);</span>
<span id="cb84-94"><a href="#cb84-94"></a>  consteval bool is_trivially_copyable(info type);</span>
<span id="cb84-95"><a href="#cb84-95"></a>  consteval bool is_standard_layout(info type);</span>
<span id="cb84-96"><a href="#cb84-96"></a>  consteval bool is_empty(info type);</span>
<span id="cb84-97"><a href="#cb84-97"></a>  consteval bool is_polymorphic(info type);</span>
<span id="cb84-98"><a href="#cb84-98"></a>  consteval bool is_abstract(info type);</span>
<span id="cb84-99"><a href="#cb84-99"></a>  consteval bool is_final(info type);</span>
<span id="cb84-100"><a href="#cb84-100"></a>  consteval bool is_aggregate(info type);</span>
<span id="cb84-101"><a href="#cb84-101"></a>  consteval bool is_signed(info type);</span>
<span id="cb84-102"><a href="#cb84-102"></a>  consteval bool is_unsigned(info type);</span>
<span id="cb84-103"><a href="#cb84-103"></a>  consteval bool is_bounded_array(info type);</span>
<span id="cb84-104"><a href="#cb84-104"></a>  consteval bool is_unbounded_array(info type);</span>
<span id="cb84-105"><a href="#cb84-105"></a>  consteval bool is_scoped_enum(info type);</span>
<span id="cb84-106"><a href="#cb84-106"></a></span>
<span id="cb84-107"><a href="#cb84-107"></a>  consteval bool is_constructible(info type, span&lt;info const&gt; type_args);</span>
<span id="cb84-108"><a href="#cb84-108"></a>  consteval bool is_default_constructible(info type);</span>
<span id="cb84-109"><a href="#cb84-109"></a>  consteval bool is_copy_constructible(info type);</span>
<span id="cb84-110"><a href="#cb84-110"></a>  consteval bool is_move_constructible(info type);</span>
<span id="cb84-111"><a href="#cb84-111"></a></span>
<span id="cb84-112"><a href="#cb84-112"></a>  consteval bool is_assignable(info dst_type, info src_type);</span>
<span id="cb84-113"><a href="#cb84-113"></a>  consteval bool is_copy_assignable(info type);</span>
<span id="cb84-114"><a href="#cb84-114"></a>  consteval bool is_move_assignable(info type);</span>
<span id="cb84-115"><a href="#cb84-115"></a></span>
<span id="cb84-116"><a href="#cb84-116"></a>  consteval bool is_swappable_with(info dst_type, info src_type);</span>
<span id="cb84-117"><a href="#cb84-117"></a>  consteval bool is_swappable(info type);</span>
<span id="cb84-118"><a href="#cb84-118"></a></span>
<span id="cb84-119"><a href="#cb84-119"></a>  consteval bool is_destructible(info type);</span>
<span id="cb84-120"><a href="#cb84-120"></a></span>
<span id="cb84-121"><a href="#cb84-121"></a>  consteval bool is_trivially_constructible(info type, span&lt;info const&gt; type_args);</span>
<span id="cb84-122"><a href="#cb84-122"></a>  consteval bool is_trivially_default_constructible(info type);</span>
<span id="cb84-123"><a href="#cb84-123"></a>  consteval bool is_trivially_copy_constructible(info type);</span>
<span id="cb84-124"><a href="#cb84-124"></a>  consteval bool is_trivially_move_constructible(info type);</span>
<span id="cb84-125"><a href="#cb84-125"></a></span>
<span id="cb84-126"><a href="#cb84-126"></a>  consteval bool is_trivially_assignable(info dst_type, info src_type);</span>
<span id="cb84-127"><a href="#cb84-127"></a>  consteval bool is_trivially_copy_assignable(info type);</span>
<span id="cb84-128"><a href="#cb84-128"></a>  consteval bool is_trivially_move_assignable(info type);</span>
<span id="cb84-129"><a href="#cb84-129"></a>  consteval bool is_trivially_destructible(info type);</span>
<span id="cb84-130"><a href="#cb84-130"></a></span>
<span id="cb84-131"><a href="#cb84-131"></a>  consteval bool is_nothrow_constructible(info type, span&lt;info const&gt; type_args);</span>
<span id="cb84-132"><a href="#cb84-132"></a>  consteval bool is_nothrow_default_constructible(info type);</span>
<span id="cb84-133"><a href="#cb84-133"></a>  consteval bool is_nothrow_copy_constructible(info type);</span>
<span id="cb84-134"><a href="#cb84-134"></a>  consteval bool is_nothrow_move_constructible(info type);</span>
<span id="cb84-135"><a href="#cb84-135"></a></span>
<span id="cb84-136"><a href="#cb84-136"></a>  consteval bool is_nothrow_assignable(info dst_type, info src_type);</span>
<span id="cb84-137"><a href="#cb84-137"></a>  consteval bool is_nothrow_copy_assignable(info type);</span>
<span id="cb84-138"><a href="#cb84-138"></a>  consteval bool is_nothrow_move_assignable(info type);</span>
<span id="cb84-139"><a href="#cb84-139"></a></span>
<span id="cb84-140"><a href="#cb84-140"></a>  consteval bool is_nothrow_swappable_with(info dst_type, info src_type);</span>
<span id="cb84-141"><a href="#cb84-141"></a>  consteval bool is_nothrow_swappable(info type);</span>
<span id="cb84-142"><a href="#cb84-142"></a></span>
<span id="cb84-143"><a href="#cb84-143"></a>  consteval bool is_nothrow_destructible(info type);</span>
<span id="cb84-144"><a href="#cb84-144"></a></span>
<span id="cb84-145"><a href="#cb84-145"></a>  consteval bool is_implicit_lifetime(info type);</span>
<span id="cb84-146"><a href="#cb84-146"></a></span>
<span id="cb84-147"><a href="#cb84-147"></a>  consteval bool has_virtual_destructor(info type);</span>
<span id="cb84-148"><a href="#cb84-148"></a></span>
<span id="cb84-149"><a href="#cb84-149"></a>  consteval bool has_unique_object_representations(info type);</span>
<span id="cb84-150"><a href="#cb84-150"></a></span>
<span id="cb84-151"><a href="#cb84-151"></a>  consteval bool reference_constructs_from_temporary(info dst_type, info src_type);</span>
<span id="cb84-152"><a href="#cb84-152"></a>  consteval bool reference_converts_from_temporary(info dst_type, info src_type);</span>
<span id="cb84-153"><a href="#cb84-153"></a></span>
<span id="cb84-154"><a href="#cb84-154"></a>  // [meta.reflection.unary.prop.query], type property queries</span>
<span id="cb84-155"><a href="#cb84-155"></a>  consteval size_t alignment_of(info type);</span>
<span id="cb84-156"><a href="#cb84-156"></a>  consteval size_t rank(info type);</span>
<span id="cb84-157"><a href="#cb84-157"></a>  consteval size_t extent(info type, unsigned i = 0);</span>
<span id="cb84-158"><a href="#cb84-158"></a></span>
<span id="cb84-159"><a href="#cb84-159"></a>  // [meta.reflection.rel], type relations</span>
<span id="cb84-160"><a href="#cb84-160"></a>  consteval bool is_same(info type1, info type2);</span>
<span id="cb84-161"><a href="#cb84-161"></a>  consteval bool is_base_of(info base_type, info derived_type);</span>
<span id="cb84-162"><a href="#cb84-162"></a>  consteval bool is_convertible(info src_type, info dst_type);</span>
<span id="cb84-163"><a href="#cb84-163"></a>  consteval bool is_nothrow_convertible(info src_type, info dst_type);</span>
<span id="cb84-164"><a href="#cb84-164"></a>  consteval bool is_layout_compatible(info type1, info type2);</span>
<span id="cb84-165"><a href="#cb84-165"></a>  consteval bool is_pointer_interconvertible_base_of(info base_type, info derived_type);</span>
<span id="cb84-166"><a href="#cb84-166"></a></span>
<span id="cb84-167"><a href="#cb84-167"></a>  consteval bool is_invocable(info type, span&lt;const info&gt; type_args);</span>
<span id="cb84-168"><a href="#cb84-168"></a>  consteval bool is_invocable_r(info result_type, info type, span&lt;const info&gt; type_args);</span>
<span id="cb84-169"><a href="#cb84-169"></a></span>
<span id="cb84-170"><a href="#cb84-170"></a>  consteval bool is_nothrow_invocable(info type, span&lt;const info&gt; type_args);</span>
<span id="cb84-171"><a href="#cb84-171"></a>  consteval bool is_nothrow_invocable_r(info result_type, info type, span&lt;const info&gt; type_args);</span>
<span id="cb84-172"><a href="#cb84-172"></a></span>
<span id="cb84-173"><a href="#cb84-173"></a>  // [meta.reflection.trans.cv], const-volatile modifications</span>
<span id="cb84-174"><a href="#cb84-174"></a>  consteval info remove_const(info type);</span>
<span id="cb84-175"><a href="#cb84-175"></a>  consteval info remove_volatile(info type);</span>
<span id="cb84-176"><a href="#cb84-176"></a>  consteval info remove_cv(info type);</span>
<span id="cb84-177"><a href="#cb84-177"></a>  consteval info add_const(info type);</span>
<span id="cb84-178"><a href="#cb84-178"></a>  consteval info add_volatile(info type);</span>
<span id="cb84-179"><a href="#cb84-179"></a>  consteval info add_cv(info type);</span>
<span id="cb84-180"><a href="#cb84-180"></a></span>
<span id="cb84-181"><a href="#cb84-181"></a>  // [meta.reflection.trans.ref], reference modifications</span>
<span id="cb84-182"><a href="#cb84-182"></a>  consteval info remove_reference(info type);</span>
<span id="cb84-183"><a href="#cb84-183"></a>  consteval info add_lvalue_reference(info type);</span>
<span id="cb84-184"><a href="#cb84-184"></a>  consteval info add_rvalue_reference(info type);</span>
<span id="cb84-185"><a href="#cb84-185"></a></span>
<span id="cb84-186"><a href="#cb84-186"></a>  // [meta.reflection.trans.sign], sign modifications</span>
<span id="cb84-187"><a href="#cb84-187"></a>  consteval info make_signed(info type);</span>
<span id="cb84-188"><a href="#cb84-188"></a>  consteval info make_unsigned(info type);</span>
<span id="cb84-189"><a href="#cb84-189"></a></span>
<span id="cb84-190"><a href="#cb84-190"></a>  // [meta.reflection.trans.arr], array modifications</span>
<span id="cb84-191"><a href="#cb84-191"></a>  consteval info remove_extent(info type);</span>
<span id="cb84-192"><a href="#cb84-192"></a>  consteval info remove_all_extents(info type);</span>
<span id="cb84-193"><a href="#cb84-193"></a></span>
<span id="cb84-194"><a href="#cb84-194"></a>  // [meta.reflection.trans.ptr], pointer modifications</span>
<span id="cb84-195"><a href="#cb84-195"></a>  consteval info remove_pointer(info type);</span>
<span id="cb84-196"><a href="#cb84-196"></a>  consteval info add_pointer(info type);</span>
<span id="cb84-197"><a href="#cb84-197"></a></span>
<span id="cb84-198"><a href="#cb84-198"></a>  // [meta.reflection.trans.other], other transformations</span>
<span id="cb84-199"><a href="#cb84-199"></a>  consteval info remove_cvref(info type);</span>
<span id="cb84-200"><a href="#cb84-200"></a>  consteval info decay(info type);</span>
<span id="cb84-201"><a href="#cb84-201"></a>  consteval info common_type(span&lt;const info&gt; type_args);</span>
<span id="cb84-202"><a href="#cb84-202"></a>  consteval info common_reference(span&lt;const info&gt; type_args);</span>
<span id="cb84-203"><a href="#cb84-203"></a>  consteval info underlying_type(info type);</span>
<span id="cb84-204"><a href="#cb84-204"></a>  consteval info invoke_result(info type, span&lt;const info&gt; type_args);</span>
<span id="cb84-205"><a href="#cb84-205"></a>  consteval info unwrap_reference(info type);</span>
<span id="cb84-206"><a href="#cb84-206"></a>  consteval info unwrap_ref_decay(info type);</span>
<span id="cb84-207"><a href="#cb84-207"></a>}</span></code></pre></div>
</div>
</blockquote>
<h3 data-number="5.2.3" id="meta.reflection.names-reflection-names-and-locations"><span class="header-section-number">5.2.3</span> [meta.reflection.names] Reflection names and locations<a href="#meta.reflection.names-reflection-names-and-locations" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb85"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb85-1"><a href="#cb85-1"></a><span class="kw">consteval</span> string_view name_of<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb85-2"><a href="#cb85-2"></a><span class="kw">consteval</span> string_view qualified_name_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_61" id="pnum_61">1</a></span> <em>Returns</em>: If <code class="sourceCode cpp">r</code> designates a declared entity <code class="sourceCode cpp">X</code>, then the unqualified and qualified names of <code class="sourceCode cpp">X</code>, respectively. Otherwise, an empty <code class="sourceCode cpp">string_view</code>.</p>
<div class="sourceCode" id="cb86"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb86-1"><a href="#cb86-1"></a><span class="kw">consteval</span> string_view display_name_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_62" id="pnum_62">2</a></span> <em>Returns</em>: An implementation-defined string suitable for identifying the reflected construct.</p>
<div class="sourceCode" id="cb87"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb87-1"><a href="#cb87-1"></a><span class="kw">consteval</span> source_location source_location_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_63" id="pnum_63">3</a></span> <em>Returns</em>: An implementation-defined <code class="sourceCode cpp">source_location</code> corresponding to the reflected construct.</p>
</div>
</blockquote>
<h3 data-number="5.2.4" id="meta.reflection.queries-reflection-queries"><span class="header-section-number">5.2.4</span> [meta.reflection.queries] Reflection queries<a href="#meta.reflection.queries-reflection-queries" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb88"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb88-1"><a href="#cb88-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_public<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb88-2"><a href="#cb88-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_protected<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb88-3"><a href="#cb88-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_private<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_64" id="pnum_64">1</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a class member or base class that is public, protected, or private, respectively. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb89"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb89-1"><a href="#cb89-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_accessible<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_65" id="pnum_65">2</a></span> <em>Returns</em>: TODO</p>
<div class="sourceCode" id="cb90"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb90-1"><a href="#cb90-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_virtual<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_66" id="pnum_66">3</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a either a virtual member function or a virtual base class. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb91"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb91-1"><a href="#cb91-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_pure_virtual<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb91-2"><a href="#cb91-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_override<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_67" id="pnum_67">4</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a member function that is pure virtual or overrides another member function, respectively. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb92"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb92-1"><a href="#cb92-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_deleted<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_68" id="pnum_68">5</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a function or member function that is defined as deleted. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb93"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb93-1"><a href="#cb93-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_defaulted<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_69" id="pnum_69">6</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a member function that is defined as defaulted. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb94"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb94-1"><a href="#cb94-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_explicit<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_70" id="pnum_70">7</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a member function that is declared explicit. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb95"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb95-1"><a href="#cb95-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_bit_field<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_71" id="pnum_71">8</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a bit-field. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb96"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb96-1"><a href="#cb96-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_static_storage_duration<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_72" id="pnum_72">9</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates an object that has static storage duration. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb97"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb97-1"><a href="#cb97-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_internal_linkage<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb97-2"><a href="#cb97-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_external_linkage<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb97-3"><a href="#cb97-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_linkage<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_73" id="pnum_73">10</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates an entity that has internal linkage, external linkage, or any linkage, respectively ([basic.link]). Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb98"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb98-1"><a href="#cb98-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_namespace<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_74" id="pnum_74">11</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a namespace or namespace alias. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb99"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb99-1"><a href="#cb99-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_function<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_75" id="pnum_75">12</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a function or member function. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb100"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb100-1"><a href="#cb100-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_variable<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_76" id="pnum_76">13</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a variable. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb101"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb101-1"><a href="#cb101-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_type<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_77" id="pnum_77">14</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a type or a type alias. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb102"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb102-1"><a href="#cb102-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_alias<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_78" id="pnum_78">15</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a type alias, alias template, or namespace alias. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb103"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb103-1"><a href="#cb103-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_incomplete_type<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_79" id="pnum_79">16</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">delias<span class="op">(</span>r<span class="op">)</span></code> designates an incomplete type. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb104"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb104-1"><a href="#cb104-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_template<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_80" id="pnum_80">17</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a function template, class template, variable template, or alias template. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_81" id="pnum_81">18</a></span> <span class="note"><span>[ <em>Note 1:</em> </span>A template specialization is not a template. <code class="sourceCode cpp">is_template<span class="op">(^</span>std<span class="op">::</span>vector<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code> but <code class="sourceCode cpp">is_template<span class="op">(^</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;)</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>.<span> — <em>end note</em> ]</span></span></p>
<div class="sourceCode" id="cb105"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb105-1"><a href="#cb105-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_function_template<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb105-2"><a href="#cb105-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_variable_template<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb105-3"><a href="#cb105-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_class_template<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb105-4"><a href="#cb105-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_alias_template<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb105-5"><a href="#cb105-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_concept<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_82" id="pnum_82">19</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a function template, class template, variable template, alias template, or concept, respectively. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb106"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb106-1"><a href="#cb106-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_template_arguments<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_83" id="pnum_83">20</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates an instantiation of a function template, variable template, class template, or an alias template. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb107"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb107-1"><a href="#cb107-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> is_class_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb107-2"><a href="#cb107-2"></a><span class="kw">consteval</span> <span class="kw">auto</span> is_namespace_member<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb107-3"><a href="#cb107-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nonstatic_data_member<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb107-4"><a href="#cb107-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_static_member<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb107-5"><a href="#cb107-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_base<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb107-6"><a href="#cb107-6"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_constructor<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb107-7"><a href="#cb107-7"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_destructor<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb107-8"><a href="#cb107-8"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_special_member<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_84" id="pnum_84">21</a></span> <em>Returns</em>: <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">r</code> designates a class member, namespace member, non-static data member, static member, base class member, constructor, destructor, or special member, respectively. Otherwise, <code class="sourceCode cpp"><span class="kw">false</span></code>.</p>
<div class="sourceCode" id="cb108"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb108-1"><a href="#cb108-1"></a><span class="kw">consteval</span> info type_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_85" id="pnum_85">22</a></span> <em>Mandates</em>: <code class="sourceCode cpp">r</code> designates a typed entity.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_86" id="pnum_86">23</a></span> <em>Returns</em>: A reflection of the type of that entity.</p>
<div class="sourceCode" id="cb109"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb109-1"><a href="#cb109-1"></a><span class="kw">consteval</span> info parent_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_87" id="pnum_87">24</a></span> <em>Mandates</em>: <code class="sourceCode cpp">r</code> designates a member of a class or a namespace.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_88" id="pnum_88">25</a></span> <em>Returns</em>: A reflection of the that entity’s immediately enclosing class or namespace.</p>
<div class="sourceCode" id="cb110"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb110-1"><a href="#cb110-1"></a><span class="kw">consteval</span> info dealias<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_89" id="pnum_89">26</a></span> <em>Returns</em>: If <code class="sourceCode cpp">r</code> designates a type alias or a namespace alias, a reflection designating the underlying entity. Otherwise, <code class="sourceCode cpp">r</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_90" id="pnum_90">27</a></span> [<em>Example</em></p>
<div class="sourceCode" id="cb111"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb111-1"><a href="#cb111-1"></a>using X = int;</span>
<span id="cb111-2"><a href="#cb111-2"></a>using Y = X;</span>
<span id="cb111-3"><a href="#cb111-3"></a>static_assert(dealias(^int) == ^int);</span>
<span id="cb111-4"><a href="#cb111-4"></a>static_assert(dealias(^X) == ^int);</span>
<span id="cb111-5"><a href="#cb111-5"></a>static_assert(dealias(^Y) == ^int);</span></code></pre></div>
<p>-<em>end example</em>]</p>
<div class="sourceCode" id="cb112"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb112-1"><a href="#cb112-1"></a><span class="kw">consteval</span> info template_of<span class="op">(</span>info r<span class="op">)</span>;</span>
<span id="cb112-2"><a href="#cb112-2"></a><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> template_arguments_of<span class="op">(</span>info r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_91" id="pnum_91">28</a></span> <em>Mandates</em>: <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><span class="marginalizedparent"><a class="marginalized" href="#pnum_92" id="pnum_92">29</a></span> <em>Returns</em>: A reflection of the template of <code class="sourceCode cpp">r</code>, and the reflections of the template arguments of the specialization designated by <code class="sourceCode cpp">r</code>, respectively.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_93" id="pnum_93">30</a></span> [<em>Example</em>:</p>
<div class="sourceCode" id="cb113"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb113-1"><a href="#cb113-1"></a>template &lt;class T, class U=T&gt; struct Pair { };</span>
<span id="cb113-2"><a href="#cb113-2"></a>template &lt;class T&gt; using PairPtr = Pair&lt;T*&gt;;</span>
<span id="cb113-3"><a href="#cb113-3"></a></span>
<span id="cb113-4"><a href="#cb113-4"></a>static_assert(template_of(^Pair&lt;int&gt;) == ^Pair);</span>
<span id="cb113-5"><a href="#cb113-5"></a>static_assert(template_arguments_of(^Pair&lt;int&gt;).size() == 2);</span>
<span id="cb113-6"><a href="#cb113-6"></a></span>
<span id="cb113-7"><a href="#cb113-7"></a>static_assert(template_of(^PairPtr&lt;int&gt;) == ^PairPtr);</span>
<span id="cb113-8"><a href="#cb113-8"></a>static_assert(template_arguments_of(^PairPtr&lt;int&gt;).size() == 1);</span></code></pre></div>
<p>-<em>end example</em>]</p>
</div>
</blockquote>
<h3 data-number="5.2.5" id="meta.reflection.member.queries-reflection-member-queries"><span class="header-section-number">5.2.5</span> [meta.reflection.member.queries], Reflection member queries<a href="#meta.reflection.member.queries-reflection-member-queries" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb114"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb114-1"><a href="#cb114-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Fs<span class="op">&gt;</span></span>
<span id="cb114-2"><a href="#cb114-2"></a>  <span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> members_of<span class="op">(</span>info r, Fs<span class="op">...</span> filters<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_94" id="pnum_94">1</a></span> <em>Mandates</em>: <code class="sourceCode cpp">r</code> is a reflection designating either a class type or a namespace and <code class="sourceCode cpp"><span class="op">(</span>std<span class="op">::</span>predicate<span class="op">&lt;</span>Fs, info<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_95" id="pnum_95">2</a></span> <em>Returns</em>: A <code class="sourceCode cpp">vector</code> containing the reflections of all the direct members <code class="sourceCode cpp">m</code> of the entity designated by <code class="sourceCode cpp">r</code> such that <code class="sourceCode cpp"><span class="op">(</span>filters<span class="op">(</span>m<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. Data members are returned in the order in which they are declared, but the order of member functions and member types is unspecified. <span class="note"><span>[ <em>Note 1:</em> </span>Base classes are not members.<span> — <em>end note</em> ]</span></span></p>
<div class="sourceCode" id="cb115"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb115-1"><a href="#cb115-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Fs<span class="op">&gt;</span></span>
<span id="cb115-2"><a href="#cb115-2"></a>  <span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> bases_of<span class="op">(</span>info type, Fs<span class="op">...</span> filters<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_96" id="pnum_96">3</a></span> <em>Mandates</em>: <code class="sourceCode cpp">type</code> designates a type and <code class="sourceCode cpp"><span class="op">(</span>std<span class="op">::</span>predicate<span class="op">&lt;</span>Fs, info<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_97" id="pnum_97">4</a></span> <em>Returns</em>: Let <code class="sourceCode cpp">C</code> be the type designated by <code class="sourceCode cpp">type</code>. A <code class="sourceCode cpp">vector</code> containing the reflections of all the direct base classes, if any, of <code class="sourceCode cpp">C</code> such that <code class="sourceCode cpp"><span class="op">(</span>filters<span class="op">(</span>class_type<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. The base classes are returned in the order in which they appear the <em>base-specifier-list</em> of <code class="sourceCode cpp">C</code>.</p>
<div class="sourceCode" id="cb116"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb116-1"><a href="#cb116-1"></a><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> static_data_members_of<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_98" id="pnum_98">5</a></span> <em>Mandates</em>: <code class="sourceCode cpp">type</code> designates a type.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_99" id="pnum_99">6</a></span> <em>Effects</em>: Equivalent to: <code class="sourceCode cpp"><span class="cf">return</span> members_of<span class="op">(</span>type, is_variable<span class="op">)</span>;</code></p>
<div class="sourceCode" id="cb117"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb117-1"><a href="#cb117-1"></a><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> nonstatic_data_members_of<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_100" id="pnum_100">7</a></span> <em>Mandates</em>: <code class="sourceCode cpp">type</code> designates a type.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_101" id="pnum_101">8</a></span> <em>Effects</em>: Equivalent to: <code class="sourceCode cpp"><span class="cf">return</span> members_of<span class="op">(</span>type, is_nonstatic_data_member<span class="op">)</span>;</code></p>
<div class="sourceCode" id="cb118"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb118-1"><a href="#cb118-1"></a><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> subobjects_of<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_102" id="pnum_102">9</a></span> <em>Mandates</em>: <code class="sourceCode cpp">type</code> designates a type.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_103" id="pnum_103">10</a></span> <em>Returns</em>: A <code class="sourceCode cpp">vector</code> containing all the reflections in <code class="sourceCode cpp">bases_of<span class="op">(</span>type<span class="op">)</span></code> followed by all the reflections in <code class="sourceCode cpp">nonstatic_data_members_of<span class="op">(</span>type<span class="op">)</span></code>.</p>
<div class="sourceCode" id="cb119"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb119-1"><a href="#cb119-1"></a><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> enumerators_of<span class="op">(</span>info enum_type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_104" id="pnum_104">11</a></span> <em>Mandates</em>: <code class="sourceCode cpp">enum_type</code> designates an enumeration.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_105" id="pnum_105">12</a></span> <em>Returns</em>: A <code class="sourceCode cpp">vector</code> containing the reflections of each enumerator of the enumeration designated by <code class="sourceCode cpp">enum_type</code>, in the order in which they are declared.</p>
</div>
</blockquote>
<h3 data-number="5.2.6" id="meta.reflection.unary-unary-type-traits"><span class="header-section-number">5.2.6</span> [meta.reflection.unary] Unary type traits<a href="#meta.reflection.unary-unary-type-traits" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_106" id="pnum_106">1</a></span> Subclause [meta.reflection.unary] contains consteval functions that may be used to query the properties of a type at compile time.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_107" id="pnum_107">2</a></span> For each function taking an argument of type <code class="sourceCode cpp">meta<span class="op">::</span>info</code> whose name contains <code class="sourceCode cpp">type</code>, that argument shall be a reflection of a type or type alias. For each function taking an argument of type <code class="sourceCode cpp">span<span class="op">&lt;</span><span class="kw">const</span> meta<span class="op">::</span>info<span class="op">&gt;</span></code> named <code class="sourceCode cpp">type_args</code>, each <code class="sourceCode cpp">meta<span class="op">::</span>info</code> in that <code class="sourceCode cpp">span</code> shall be a reflection of a type or a type alias.</p>
</div>
</blockquote>
<h4 data-number="5.2.6.1" id="meta.reflection.unary.cat-primary-type-categories"><span class="header-section-number">5.2.6.1</span> [meta.reflection.unary.cat] Primary type categories<a href="#meta.reflection.unary.cat-primary-type-categories" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_108" id="pnum_108">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>TRAIT</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>TRAIT</em><span class="op">(^</span>T<span class="op">)</span></code> equals the value of the corresponding unary type trait <code class="sourceCode cpp">std<span class="op">::</span><em>TRAIT</em>_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.5.2 <a href="https://wg21.link/meta.unary.cat">[meta.unary.cat]</a></span>.</p>
<div class="sourceCode" id="cb120"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb120-1"><a href="#cb120-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_void<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-2"><a href="#cb120-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_null_pointer<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-3"><a href="#cb120-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_integral<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-4"><a href="#cb120-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_floating_point<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-5"><a href="#cb120-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_array<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-6"><a href="#cb120-6"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_pointer<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-7"><a href="#cb120-7"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_lvalue_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-8"><a href="#cb120-8"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_rvalue_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-9"><a href="#cb120-9"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_member_object_pointer<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-10"><a href="#cb120-10"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_member_function_pointer<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-11"><a href="#cb120-11"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_enum<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-12"><a href="#cb120-12"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_union<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-13"><a href="#cb120-13"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_class<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb120-14"><a href="#cb120-14"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_function<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_109" id="pnum_109">2</a></span> [<em>Example</em></p>
<div class="sourceCode" id="cb121"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb121-1"><a href="#cb121-1"></a>// an example implementation</span>
<span id="cb121-2"><a href="#cb121-2"></a>namespace std::meta {</span>
<span id="cb121-3"><a href="#cb121-3"></a>  consteval bool is_void(info type) {</span>
<span id="cb121-4"><a href="#cb121-4"></a>    return value_of&lt;bool&gt;(substitute(^is_void_v, {type}));</span>
<span id="cb121-5"><a href="#cb121-5"></a>  }</span>
<span id="cb121-6"><a href="#cb121-6"></a>}</span></code></pre></div>
<p><em>-end example</em>]</p>
</div>
</blockquote>
<h4 data-number="5.2.6.2" id="meta.reflection.unary.comp-composite-type-categories"><span class="header-section-number">5.2.6.2</span> [meta.reflection.unary.comp] Composite type categories<a href="#meta.reflection.unary.comp-composite-type-categories" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_110" id="pnum_110">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>TRAIT</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>TRAIT</em><span class="op">(^</span>T<span class="op">)</span></code> equals the value of the corresponding unary type trait <code class="sourceCode cpp">std<span class="op">::</span><em>TRAIT</em>_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.5.3 <a href="https://wg21.link/meta.unary.comp">[meta.unary.comp]</a></span>.</p>
<div class="sourceCode" id="cb122"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb122-1"><a href="#cb122-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-2"><a href="#cb122-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_arithmetic<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-3"><a href="#cb122-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_fundamental<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-4"><a href="#cb122-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_object<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-5"><a href="#cb122-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_scalar<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-6"><a href="#cb122-6"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_compound<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb122-7"><a href="#cb122-7"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_member_pointer<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.6.3" id="meta.reflection.unary.prop-type-properties"><span class="header-section-number">5.2.6.3</span> [meta.reflection.unary.prop] Type properties<a href="#meta.reflection.unary.prop-type-properties" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_111" id="pnum_111">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>UNARY-TRAIT</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>UNARY-TRAIT</em><span class="op">(^</span>T<span class="op">)</span></code> equals the value of the corresponding type property <code class="sourceCode cpp">std<span class="op">::</span><em>UNARY-TRAIT</em>_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.5.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_112" id="pnum_112">2</a></span> For any types <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">U</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>BINARY-TRAIT</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>BINARY-TRAIT</em><span class="op">(^</span>T, <span class="op">^</span>U<span class="op">)</span></code> equals the value of the corresponding type property <code class="sourceCode cpp">std<span class="op">::</span><em>BINARY-TRAIT</em>_v<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> as specified in <span>21.3.5.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_113" id="pnum_113">3</a></span> For any type <code class="sourceCode cpp">T</code> and pack of types <code class="sourceCode cpp">U<span class="op">...</span></code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-TRAIT</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-TRAIT</em><span class="op">(^</span>T, <span class="op">{^</span>U<span class="op">...})</span></code> equals the value of the corresponding type property <code class="sourceCode cpp">std<span class="op">::</span><em>VARIADIC-TRAIT</em>_v<span class="op">&lt;</span>T, U<span class="op">...&gt;</span></code> as specified in <span>21.3.5.4 <a href="https://wg21.link/meta.unary.prop">[meta.unary.prop]</a></span>.</p>
<div class="sourceCode" id="cb123"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb123-1"><a href="#cb123-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_const<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-2"><a href="#cb123-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_volatile<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-3"><a href="#cb123-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivial<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-4"><a href="#cb123-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_copyable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-5"><a href="#cb123-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_standard_layout<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-6"><a href="#cb123-6"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_empty<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-7"><a href="#cb123-7"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_polymorphic<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-8"><a href="#cb123-8"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_abstract<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-9"><a href="#cb123-9"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_final<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-10"><a href="#cb123-10"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_aggregate<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-11"><a href="#cb123-11"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_signed<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-12"><a href="#cb123-12"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_unsigned<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-13"><a href="#cb123-13"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_bounded_array<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-14"><a href="#cb123-14"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_unbounded_array<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-15"><a href="#cb123-15"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_scoped_enum<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-16"><a href="#cb123-16"></a></span>
<span id="cb123-17"><a href="#cb123-17"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_constructible<span class="op">(</span>info type, span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb123-18"><a href="#cb123-18"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_default_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-19"><a href="#cb123-19"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_copy_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-20"><a href="#cb123-20"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_move_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-21"><a href="#cb123-21"></a></span>
<span id="cb123-22"><a href="#cb123-22"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_assignable<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-23"><a href="#cb123-23"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_copy_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-24"><a href="#cb123-24"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_move_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-25"><a href="#cb123-25"></a></span>
<span id="cb123-26"><a href="#cb123-26"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_swappable_with<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-27"><a href="#cb123-27"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_swappable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-28"><a href="#cb123-28"></a></span>
<span id="cb123-29"><a href="#cb123-29"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_destructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-30"><a href="#cb123-30"></a></span>
<span id="cb123-31"><a href="#cb123-31"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_constructible<span class="op">(</span>info type, span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb123-32"><a href="#cb123-32"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_default_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-33"><a href="#cb123-33"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_copy_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-34"><a href="#cb123-34"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_move_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-35"><a href="#cb123-35"></a></span>
<span id="cb123-36"><a href="#cb123-36"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_assignable<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-37"><a href="#cb123-37"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_copy_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-38"><a href="#cb123-38"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_move_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-39"><a href="#cb123-39"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_trivially_destructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-40"><a href="#cb123-40"></a></span>
<span id="cb123-41"><a href="#cb123-41"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_constructible<span class="op">(</span>info type, span<span class="op">&lt;</span>info <span class="kw">const</span><span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb123-42"><a href="#cb123-42"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_default_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-43"><a href="#cb123-43"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_copy_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-44"><a href="#cb123-44"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_move_constructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-45"><a href="#cb123-45"></a></span>
<span id="cb123-46"><a href="#cb123-46"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_assignable<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-47"><a href="#cb123-47"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_copy_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-48"><a href="#cb123-48"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_move_assignable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-49"><a href="#cb123-49"></a></span>
<span id="cb123-50"><a href="#cb123-50"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_swappable_with<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-51"><a href="#cb123-51"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_swappable<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-52"><a href="#cb123-52"></a></span>
<span id="cb123-53"><a href="#cb123-53"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_destructible<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-54"><a href="#cb123-54"></a></span>
<span id="cb123-55"><a href="#cb123-55"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_implicit_lifetime<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-56"><a href="#cb123-56"></a></span>
<span id="cb123-57"><a href="#cb123-57"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_virtual_destructor<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-58"><a href="#cb123-58"></a></span>
<span id="cb123-59"><a href="#cb123-59"></a><span class="kw">consteval</span> <span class="dt">bool</span> has_unique_object_representations<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb123-60"><a href="#cb123-60"></a></span>
<span id="cb123-61"><a href="#cb123-61"></a><span class="kw">consteval</span> <span class="dt">bool</span> reference_constructs_from_temporary<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span>
<span id="cb123-62"><a href="#cb123-62"></a><span class="kw">consteval</span> <span class="dt">bool</span> reference_converts_from_temporary<span class="op">(</span>info dst_type, info src_type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.6.4" id="meta.reflection.unary.prop.query-type-property-queries"><span class="header-section-number">5.2.6.4</span> [meta.reflection.unary.prop.query] Type property queries<a href="#meta.reflection.unary.prop.query-type-property-queries" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_114" id="pnum_114">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>PROP</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">size_t</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>PROP</em><span class="op">(^</span>T<span class="op">)</span></code> equals the value of the corresponding type property <code class="sourceCode cpp">std<span class="op">::</span><em>PROP</em>_v<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.6 <a href="https://wg21.link/meta.unary.prop.query">[meta.unary.prop.query]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_115" id="pnum_115">2</a></span> For any type <code class="sourceCode cpp">T</code> and unsigned integer value <code class="sourceCode cpp">I</code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>extent<span class="op">(^</span>T, I<span class="op">)</span></code> equals <code class="sourceCode cpp">std<span class="op">::</span>extent_v<span class="op">&lt;</span>T, I<span class="op">&gt;</span></code> ([meta.unary.prop.query]).</p>
<div class="sourceCode" id="cb124"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb124-1"><a href="#cb124-1"></a><span class="kw">consteval</span> <span class="dt">size_t</span> alignment_of<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb124-2"><a href="#cb124-2"></a><span class="kw">consteval</span> <span class="dt">size_t</span> rank<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb124-3"><a href="#cb124-3"></a><span class="kw">consteval</span> <span class="dt">size_t</span> extent<span class="op">(</span>info type, <span class="dt">unsigned</span> i <span class="op">=</span> <span class="dv">0</span><span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h3 data-number="5.2.7" id="meta.reflection.rel-type-relations"><span class="header-section-number">5.2.7</span> [meta.reflection.rel], Type relations<a href="#meta.reflection.rel-type-relations" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_116" id="pnum_116">1</a></span> The consteval functions specified in this clause may be used to query relationships between types at compile time.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_117" id="pnum_117">2</a></span> For any types <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">U</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>REL</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>REL</em><span class="op">(^</span>T, <span class="op">^</span>U<span class="op">)</span></code> equals the value of the corresponding type relation <code class="sourceCode cpp">std<span class="op">::</span><em>REL</em>_v<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> as specified in <span>21.3.7 <a href="https://wg21.link/meta.rel">[meta.rel]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_118" id="pnum_118">3</a></span> For any type <code class="sourceCode cpp">T</code> and pack of types <code class="sourceCode cpp">U<span class="op">...</span></code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-REL</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-REL</em><span class="op">(^</span>T, <span class="op">{^</span>U<span class="op">...})</span></code> equals the value of the corresponding type relation <code class="sourceCode cpp">std<span class="op">::</span><em>VARIADIC-REL</em>_v<span class="op">&lt;</span>T, U<span class="op">...&gt;</span></code> as specified in <span>21.3.7 <a href="https://wg21.link/meta.rel">[meta.rel]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_119" id="pnum_119">4</a></span> For any types <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">R</code> and pack of types <code class="sourceCode cpp">U<span class="op">...</span></code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-REL-R</em></code> defined in this clause with signature <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>meta<span class="op">::</span>info, std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-REL-R</em><span class="op">(^</span>R, <span class="op">^</span>T, <span class="op">{^</span>U<span class="op">...})</span></code> equals the value of the corresponding type relation <code class="sourceCode cpp">std<span class="op">::</span><em>VARIADIC-REL-R</em>_v<span class="op">&lt;</span>R, T, U<span class="op">...&gt;</span></code> as specified in <span>21.3.7 <a href="https://wg21.link/meta.rel">[meta.rel]</a></span>.</p>
<div class="sourceCode" id="cb125"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb125-1"><a href="#cb125-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_same<span class="op">(</span>info type1, info type2<span class="op">)</span>;</span>
<span id="cb125-2"><a href="#cb125-2"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_base_of<span class="op">(</span>info base_type, info derived_type<span class="op">)</span>;</span>
<span id="cb125-3"><a href="#cb125-3"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_convertible<span class="op">(</span>info src_type, info dst_type<span class="op">)</span>;</span>
<span id="cb125-4"><a href="#cb125-4"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_convertible<span class="op">(</span>info src_type, info dst_type<span class="op">)</span>;</span>
<span id="cb125-5"><a href="#cb125-5"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_layout_compatible<span class="op">(</span>info type1, info type2<span class="op">)</span>;</span>
<span id="cb125-6"><a href="#cb125-6"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_pointer_interconvertible_base_of<span class="op">(</span>info base_type, info derived_type<span class="op">)</span>;</span>
<span id="cb125-7"><a href="#cb125-7"></a></span>
<span id="cb125-8"><a href="#cb125-8"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_invocable<span class="op">(</span>info type, span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb125-9"><a href="#cb125-9"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_invocable_r<span class="op">(</span>info result_type, info type, span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb125-10"><a href="#cb125-10"></a></span>
<span id="cb125-11"><a href="#cb125-11"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_invocable<span class="op">(</span>info type, span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb125-12"><a href="#cb125-12"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_nothrow_invocable_r<span class="op">(</span>info result_type, info type, span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_120" id="pnum_120">5</a></span> <span class="note"><span>[ <em>Note 1:</em> </span>If <code class="sourceCode cpp">t</code> is a reflection of the type <code class="sourceCode cpp"><span class="dt">int</span></code> and <code class="sourceCode cpp">u</code> is a reflection of an alias to the type <code class="sourceCode cpp"><span class="dt">int</span></code>, then <code class="sourceCode cpp">t <span class="op">==</span> u</code> is <code class="sourceCode cpp"><span class="kw">false</span></code> but <code class="sourceCode cpp">is_same<span class="op">(</span>t, u<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. <code class="sourceCode cpp">t <span class="op">==</span> dealias<span class="op">(</span>u<span class="op">)</span></code> is also <code class="sourceCode cpp"><span class="kw">true</span></code>.<span> — <em>end note</em> ]</span></span>.</p>
</div>
</blockquote>
<h3 data-number="5.2.8" id="meta.reflection.trans-transformations-between-types"><span class="header-section-number">5.2.8</span> [meta.reflection.trans], Transformations between types<a href="#meta.reflection.trans-transformations-between-types" class="self-link"></a></h3>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_121" id="pnum_121">1</a></span> Subclause [meta.reflection.trans] contains consteval functions that may be used to transform one type to another following some predefined rule.</p>
</div>
</blockquote>
<h4 data-number="5.2.8.1" id="meta.reflection.trans.cv-const-volatile-modifications"><span class="header-section-number">5.2.8.1</span> [meta.reflection.trans.cv], Const-volatile modifications<a href="#meta.reflection.trans.cv-const-volatile-modifications" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_122" id="pnum_122">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.2 <a href="https://wg21.link/meta.trans.cv">[meta.trans.cv]</a></span>.</p>
<div class="sourceCode" id="cb126"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb126-1"><a href="#cb126-1"></a><span class="kw">consteval</span> info remove_const<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb126-2"><a href="#cb126-2"></a><span class="kw">consteval</span> info remove_volatile<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb126-3"><a href="#cb126-3"></a><span class="kw">consteval</span> info remove_cv<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb126-4"><a href="#cb126-4"></a><span class="kw">consteval</span> info add_const<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb126-5"><a href="#cb126-5"></a><span class="kw">consteval</span> info add_volatile<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb126-6"><a href="#cb126-6"></a><span class="kw">consteval</span> info add_cv<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.8.2" id="meta.reflection.trans.ref-reference-modifications"><span class="header-section-number">5.2.8.2</span> [meta.reflection.trans.ref], Reference modifications<a href="#meta.reflection.trans.ref-reference-modifications" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_123" id="pnum_123">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.3 <a href="https://wg21.link/meta.trans.ref">[meta.trans.ref]</a></span>.</p>
<div class="sourceCode" id="cb127"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb127-1"><a href="#cb127-1"></a><span class="kw">consteval</span> info remove_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb127-2"><a href="#cb127-2"></a><span class="kw">consteval</span> info add_lvalue_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb127-3"><a href="#cb127-3"></a><span class="kw">consteval</span> info add_rvalue_reference<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.8.3" id="meta.reflection.trans.sign-sign-modifications"><span class="header-section-number">5.2.8.3</span> [meta.reflection.trans.sign], Sign modifications<a href="#meta.reflection.trans.sign-sign-modifications" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_124" id="pnum_124">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.4 <a href="https://wg21.link/meta.trans.sign">[meta.trans.sign]</a></span>.</p>
<div class="sourceCode" id="cb128"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb128-1"><a href="#cb128-1"></a><span class="kw">consteval</span> info make_signed<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb128-2"><a href="#cb128-2"></a><span class="kw">consteval</span> info make_unsigned<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.8.4" id="meta.reflection.trans.arr-array-modifications"><span class="header-section-number">5.2.8.4</span> [meta.reflection.trans.arr], Array modifications<a href="#meta.reflection.trans.arr-array-modifications" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_125" id="pnum_125">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.5 <a href="https://wg21.link/meta.trans.arr">[meta.trans.arr]</a></span>.</p>
<div class="sourceCode" id="cb129"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb129-1"><a href="#cb129-1"></a><span class="kw">consteval</span> info remove_extent<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb129-2"><a href="#cb129-2"></a><span class="kw">consteval</span> info remove_all_extents<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.8.5" id="meta.reflection.trans.ptr-pointer-modifications"><span class="header-section-number">5.2.8.5</span> [meta.reflection.trans.ptr], Pointer modifications<a href="#meta.reflection.trans.ptr-pointer-modifications" class="self-link"></a></h4>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_126" id="pnum_126">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.6 <a href="https://wg21.link/meta.trans.ptr">[meta.trans.ptr]</a></span>.</p>
<div class="sourceCode" id="cb130"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb130-1"><a href="#cb130-1"></a><span class="kw">consteval</span> info remove_pointer<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb130-2"><a href="#cb130-2"></a><span class="kw">consteval</span> info add_pointer<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
</div>
</blockquote>
<h4 data-number="5.2.8.6" id="meta.reflection.trans.other-other-transformations"><span class="header-section-number">5.2.8.6</span> [meta.reflection.trans.other], Other transformations<a href="#meta.reflection.trans.other-other-transformations" class="self-link"></a></h4>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: There are four transformations that are deliberately omitted here. <code class="sourceCode default">type_identity</code> and <code class="sourceCode default">enable_if</code> are not useful, <code class="sourceCode default">conditional(cond, t, f)</code> would just be a long way of writing <code class="sourceCode default">cond ? t : f</code>, and <code class="sourceCode default">basic_common_reference</code> is a class template intended to be specialized and not directly invoked. ]</span></p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_127" id="pnum_127">1</a></span> For any type <code class="sourceCode cpp">T</code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em></code> defined in this clause with signature <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>MOD</em><span class="op">(^</span>T<span class="op">)</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>MOD</em>_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> as specified in <span>21.3.8.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_128" id="pnum_128">2</a></span> For any pack of types <code class="sourceCode cpp">T<span class="op">...</span></code>, for each function <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-MOD</em></code> defined in this clause with signature <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">(</span>std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;)</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span><em>VARIADIC-MOD</em><span class="op">({^</span>T<span class="op">...})</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span><em>VARIADIC-MOD</em>_t<span class="op">&lt;</span>T<span class="op">...&gt;</span></code> as specified in <span>21.3.8.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a></span>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_129" id="pnum_129">3</a></span> For any type <code class="sourceCode cpp">T</code> and pack of types <code class="sourceCode cpp">U<span class="op">...</span></code>, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>invoke_result<span class="op">(^</span>T, <span class="op">{^</span>u<span class="op">...})</span></code> returns the reflection of the corresponding type <code class="sourceCode cpp">std<span class="op">::</span>invoke_result_t<span class="op">&lt;</span>T, U<span class="op">...&gt;</span></code> (<span>21.3.8.7 <a href="https://wg21.link/meta.trans.other">[meta.trans.other]</a></span>).</p>
<div class="sourceCode" id="cb131"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb131-1"><a href="#cb131-1"></a><span class="kw">consteval</span> info remove_cvref<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb131-2"><a href="#cb131-2"></a><span class="kw">consteval</span> info decay<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb131-3"><a href="#cb131-3"></a><span class="kw">consteval</span> info common_type<span class="op">(</span>span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb131-4"><a href="#cb131-4"></a><span class="kw">consteval</span> info common_reference<span class="op">(</span>span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb131-5"><a href="#cb131-5"></a><span class="kw">consteval</span> info underlying_type<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb131-6"><a href="#cb131-6"></a><span class="kw">consteval</span> info invoke_result<span class="op">(</span>info type, span<span class="op">&lt;</span><span class="kw">const</span> info<span class="op">&gt;</span> type_args<span class="op">)</span>;</span>
<span id="cb131-7"><a href="#cb131-7"></a><span class="kw">consteval</span> info unwrap_reference<span class="op">(</span>info type<span class="op">)</span>;</span>
<span id="cb131-8"><a href="#cb131-8"></a><span class="kw">consteval</span> info unwrap_ref_decay<span class="op">(</span>info type<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_130" id="pnum_130">4</a></span> [<em>Example</em>:</p>
<div class="sourceCode" id="cb132"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb132-1"><a href="#cb132-1"></a><span class="co">// example implementation</span></span>
<span id="cb132-2"><a href="#cb132-2"></a><span class="kw">consteval</span> info unwrap_reference<span class="op">(</span>info type<span class="op">)</span> <span class="op">{</span></span>
<span id="cb132-3"><a href="#cb132-3"></a>  <span class="cf">if</span> <span class="op">(</span>has_template_arguments<span class="op">(</span>type<span class="op">)</span> <span class="op">&amp;&amp;</span> template_of<span class="op">(</span>type<span class="op">)</span> <span class="op">==</span> <span class="op">^</span>reference_wrapper<span class="op">)</span> <span class="op">{</span></span>
<span id="cb132-4"><a href="#cb132-4"></a>    <span class="cf">return</span> add_lvalue_reference<span class="op">(</span>template_arguments_of<span class="op">(</span>type<span class="op">)[</span><span class="dv">0</span><span class="op">])</span>;</span>
<span id="cb132-5"><a href="#cb132-5"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb132-6"><a href="#cb132-6"></a>    <span class="cf">return</span> type;</span>
<span id="cb132-7"><a href="#cb132-7"></a>  <span class="op">}</span></span>
<span id="cb132-8"><a href="#cb132-8"></a><span class="op">}</span></span></code></pre></div>
<p><em>-end example</em>]</p>
</div>
</blockquote>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</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-P1240R0">
<p>[P1240R0] Andrew Sutton, Faisal Vali, Daveed Vandevoorde. 2018-10-08. Scalable Reflection in C++. <br />
<a href="https://wg21.link/p1240r0">https://wg21.link/p1240r0</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 id="ref-P2758R1">
<p>[P2758R1] Barry Revzin. 2023-12-09. Emitting messages at compile time. <br />
<a href="https://wg21.link/p2758r1">https://wg21.link/p2758r1</a></p>
</div>
<div id="ref-P2996R0">
<p>[P2996R0] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton, Faisal Vali, Daveed Vandevoorde. 2023-10-15. Reflection for C++26. <br />
<a href="https://wg21.link/p2996r0">https://wg21.link/p2996r0</a></p>
</div>
<div id="ref-P2996R1">
<p>[P2996R1] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton, Faisal Vali, Daveed Vandevoorde. 2023-12-18. Reflection for C++26. <br />
<a href="https://wg21.link/p2996r1">https://wg21.link/p2996r1</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
