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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Reflection and
meta-programming</h1>
<h3 class="subtitle" style="text-align:center">A fragment based
design</h3>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>D3435R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-10-14</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>
      Language Evolution<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Jean-Baptiste VALLON HOARAU<br>&lt;<a href="mailto:jbvallon@codereckons.com" class="email">jbvallon@codereckons.com</a>&gt;<br>
      Joel FALCOU<br>&lt;<a href="mailto:jfalcou@codereckons.com" class="email">jfalcou@codereckons.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#comparison-with-other-designs" id="toc-comparison-with-other-designs"><span class="toc-section-number">2</span> Comparison with other
designs<span></span></a>
<ul>
<li><a href="#p2996-reflection-for-c26" id="toc-p2996-reflection-for-c26"><span class="toc-section-number">2.1</span> <span>P2996 : Reflection for
C++26</span><span></span></a></li>
<li><a href="#p2237-meta-programming-with-fragments" id="toc-p2237-meta-programming-with-fragments"><span class="toc-section-number">2.2</span> <span>P2237 : Meta-programming
(with fragments)</span><span></span></a></li>
<li><a href="#p3294-code-injection-with-token-sequences" id="toc-p3294-code-injection-with-token-sequences"><span class="toc-section-number">2.3</span> <span>P3294 : Code Injection with
Token Sequences</span><span></span></a></li>
<li><a href="#our-previous-work" id="toc-our-previous-work"><span class="toc-section-number">2.4</span> Our previous
work<span></span></a></li>
<li><a href="#rust-macros-and-syn" id="toc-rust-macros-and-syn"><span class="toc-section-number">2.5</span> Rust : <span>macros</span> and
<span><code class="sourceCode cpp">syn</code></span><span></span></a></li>
</ul></li>
<li><a href="#reflection" id="toc-reflection"><span class="toc-section-number">3</span> Reflection<span></span></a>
<ul>
<li><a href="#types" id="toc-types"><span class="toc-section-number">3.1</span> Types<span></span></a></li>
<li><a href="#declarations" id="toc-declarations"><span class="toc-section-number">3.2</span> Declarations<span></span></a></li>
<li><a href="#expressions" id="toc-expressions"><span class="toc-section-number">3.3</span> Expressions<span></span></a></li>
<li><a href="#conversion-to-text-and-diagnosis" id="toc-conversion-to-text-and-diagnosis"><span class="toc-section-number">3.4</span> Conversion to text and
diagnosis<span></span></a></li>
<li><a href="#syntax-issues-the-caret-and-objective-c" id="toc-syntax-issues-the-caret-and-objective-c"><span class="toc-section-number">3.5</span> Syntax issues : the caret and
Objective-C<span></span></a></li>
</ul></li>
<li><a href="#meta-programming" id="toc-meta-programming"><span class="toc-section-number">4</span> Meta-programming<span></span></a>
<ul>
<li><a href="#expressions-1" id="toc-expressions-1"><span class="toc-section-number">4.1</span> Expressions<span></span></a></li>
<li><a href="#function-fragments" id="toc-function-fragments"><span class="toc-section-number">4.2</span> Function
fragments<span></span></a></li>
<li><a href="#injection-of-names" id="toc-injection-of-names"><span class="toc-section-number">4.3</span> Injection of
names<span></span></a></li>
<li><a href="#namespace-fragments" id="toc-namespace-fragments"><span class="toc-section-number">4.4</span> Namespace
fragments<span></span></a></li>
<li><a href="#enum-fragments" id="toc-enum-fragments"><span class="toc-section-number">4.5</span> Enum
fragments<span></span></a></li>
<li><a href="#class-fragments" id="toc-class-fragments"><span class="toc-section-number">4.6</span> Class
fragments<span></span></a></li>
<li><a href="#fragment-captures-technicals-considerations" id="toc-fragment-captures-technicals-considerations"><span class="toc-section-number">4.7</span> Fragment captures : technicals
considerations<span></span></a></li>
</ul></li>
<li><a href="#use-cases" id="toc-use-cases"><span class="toc-section-number">5</span> Use-cases<span></span></a>
<ul>
<li><a href="#enum-to-string" id="toc-enum-to-string"><span class="toc-section-number">5.1</span> Enum to
string<span></span></a></li>
<li><a href="#parsing-command-line-options" id="toc-parsing-command-line-options"><span class="toc-section-number">5.2</span> Parsing command-line
options<span></span></a></li>
<li><a href="#tuple" id="toc-tuple"><span class="toc-section-number">5.3</span> Tuple<span></span></a></li>
<li><a href="#variant" id="toc-variant"><span class="toc-section-number">5.4</span> Variant<span></span></a></li>
<li><a href="#universal-formatter" id="toc-universal-formatter"><span class="toc-section-number">5.5</span> Universal
formatter<span></span></a></li>
<li><a href="#operators-generation" id="toc-operators-generation"><span class="toc-section-number">5.6</span> Operators
generation<span></span></a></li>
<li><a href="#class-registration" id="toc-class-registration"><span class="toc-section-number">5.7</span> Class
registration<span></span></a></li>
<li><a href="#enum-flagsum-generation" id="toc-enum-flagsum-generation"><span class="toc-section-number">5.8</span> Enum flagsum
generation<span></span></a></li>
<li><a href="#members-and-overload-set-lifting" id="toc-members-and-overload-set-lifting"><span class="toc-section-number">5.9</span> Members and overload set
lifting<span></span></a></li>
<li><a href="#ensure-replacement-for-assert" id="toc-ensure-replacement-for-assert"><span class="toc-section-number">5.10</span>
<code class="sourceCode cpp">ensure</code> : replacement for
assert<span></span></a></li>
<li><a href="#cloning-types-logged-class" id="toc-cloning-types-logged-class"><span class="toc-section-number">5.11</span> Cloning types : logged
class<span></span></a></li>
</ul></li>
<li><a href="#future-work" id="toc-future-work"><span class="toc-section-number">6</span> Future work<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">7</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>We present a practical, use-cases driven design for compile time
reflection and meta-programming that has been implemented as a fork of
the Clang compiler. Reflection is powered by a set of
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
functions providing access to properties of the language, while
meta-programming is done by substitution of code fragments (not unlike
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2237r0.pdf">Andrew
Sutton’s P2237</a>, although with some differences).</p>
<p>The set of core use-cases that have informed the design includes :
operators generation, generation of interfaces for other languages
(e.g. Python), class registration, serialisation, implementation of
arithmetic types, overload set and member “lifting”, dynamic traits, a
replacement for the
<code class="sourceCode cpp"><span class="ot">assert</span></code>
macro. Ultimately, we think that meta-programming for C++ should aim to
replace preprocessor macros and custom code generators that are common
in existing C++ code.</p>
<p>This proposal is deliberately minimal and soft-edged. Minimal because
we are proposing on the reflection side what is just enough to fullfil
our meta-programming needs. Soft-edged because we are open to additions
or reductions to the set of meta-programming use cases that we present
here.</p>
<h1 data-number="2" id="comparison-with-other-designs"><span class="header-section-number">2</span> Comparison with other designs<a href="#comparison-with-other-designs" class="self-link"></a></h1>
<h2 data-number="2.1" id="p2996-reflection-for-c26"><span class="header-section-number">2.1</span> <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2996r2.html">P2996
: Reflection for C++26</a><a href="#p2996-reflection-for-c26" class="self-link"></a></h2>
<p>This design differs from <span class="citation" data-cites="P2996R5">[<a href="https://wg21.link/p2996r5" role="doc-biblioref">P2996R5</a>]</span> mostly in that it is structured
around 3 core types : <code class="sourceCode cpp">decl</code>,
<code class="sourceCode cpp">expr</code>, and
<code class="sourceCode cpp">type</code>, with additional types used to
represent properties of those 3 core types
(<code class="sourceCode cpp">identifier</code>,
<code class="sourceCode cpp">name</code>,
<code class="sourceCode cpp">source_location</code>,
<code class="sourceCode cpp">template_argument</code>, etc.). P2996
argues that using types in the reflection API is a bad idea because we
would then be unable to accomodate language evolution. We contend,
however, that the categories of language properties we base the
reflection API upon have been stable through the history of the
language, and that there is no reason to believe that a change large
enough to break it should happen. We contend that in general, weakly
typed API are harder to use and more error prone.</p>
<p>We propose the ability to reflect on and construct expressions, which
P2996 do not. This is necessary in virtually all of our use-cases.</p>
<p>Another difference is that P2996 proposes using
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
for returning ranges of properties from a reflection value. Instead, our
API uses the compiler builtins types
<code class="sourceCode cpp">expr_list</code>,
<code class="sourceCode cpp">type_list</code>,
<code class="sourceCode cpp">decl_list</code> (etc.), mostly because it
was easier to implement this way. But it turns out it has some
advantages : first, these types can be literals and even
<em>structurals</em>, so we can use them as template arguments. This is
a major advantage over using
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>,
at least until C++ has a way to expand the set of structural type to
include dynamic containers, and it’s particularly important in our
meta-programming design to have some dynamic containers that are
structural (see section 4.7). Secondly, it’s faster : all operations
done in the interpreter with
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
are done at native speed with a compiler builtin type. Finally, it frees
the reflection API from a dependency to the standard library.</p>
<p>Otherwise, the reflection functionalities proposed here are
essentially the same.</p>
<p>P2996 does not really propose a meta-programming mechanism beyond
<code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>,
so we cannot compare the twos in that aspect.</p>
<h2 data-number="2.2" id="p2237-meta-programming-with-fragments"><span class="header-section-number">2.2</span> <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2237r0.pdf">P2237
: Meta-programming (with fragments)</a><a href="#p2237-meta-programming-with-fragments" class="self-link"></a></h2>
<p>The meta-programming design put forward by Andrew Sutton in <span class="citation" data-cites="P2237R0">[<a href="https://wg21.link/p2237r0" role="doc-biblioref">P2237R0</a>]</span> is the closest to ours, and it
should come with no surprise that it has been an inspiration.</p>
<p>The most important difference is that our code fragments are
parametrised with explicit captures, removing the need for the “unquote
operator”. We also do not propose consteval blocks. Furthermore, our
injection model is based on “code builders”, which allows to inject in a
context and provides information about it.</p>
<p>P2237 touches upon the issue of using context provided names in code
fragments. In practice, we’ve found that this problem can always be
solved through passing down reflection of the declarations needed to the
injection code, or, when that proves to be too verbose, performing
lookup in the context of injection. We will talk about this in more
detail in the meta-programming section.</p>
<h2 data-number="2.3" id="p3294-code-injection-with-token-sequences"><span class="header-section-number">2.3</span> <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3294r0.html">P3294
: Code Injection with Token Sequences</a><a href="#p3294-code-injection-with-token-sequences" class="self-link"></a></h2>
<p><span class="citation" data-cites="P3294R1">[<a href="https://wg21.link/p3294r1" role="doc-biblioref">P3294R1</a>]</span> proposes a meta-programming
model based on tokens injection. While this is viable (see : Rust), the
strength of tokens based meta-programming, which is the ability to
construct any kind of code without syntactic or semantic verification,
is also its weakness. It works when it works, when it doesn’t, woe
betides the user.</p>
<p>Fragments based meta-programming obviously guarantee syntactical
correctness, but also allows the compiler to perform semantic
verification at each step of program construction.</p>
<p>P3294 points out that too much semantic checking at the point of
fragment declaration limits their usefulness, in particular with respect
to name lookup. We agree : this is why we are in favor of two-phase
lookup, and why we do not propose anything like the “required
declarations” of P2237.</p>
<p>Admittedly, our prototype cannot yet implement the LoggingVector use
case put forth by P3294. We will explore a possible solution in the last
part of the use-case section.</p>
<h2 data-number="2.4" id="our-previous-work"><span class="header-section-number">2.4</span> Our previous work<a href="#our-previous-work" class="self-link"></a></h2>
<p>We’ve previously talked about an AST-based meta-programming model <a href="https://codereckons.com/articles">in a series of blog posts</a>.
What we are presenting here is very different – we are abandoning the
previous model as a serious contender for standardisation. While it
worked, it was very cumbersome to use.</p>
<p>We also considerably reduced the reflection API surface. While we’ve
kept the core types <code class="sourceCode cpp">decl</code>,
<code class="sourceCode cpp">expr</code>, and
<code class="sourceCode cpp">type</code>, we do not propose refined
types anymore, nor do we propose statements traversal, expressions
traversal, and querying function bodies (hence the
<code class="sourceCode cpp">stmt</code> type is gone).</p>
<p>While some of that might proves to be desirable in the future, our
focus is on providing a replacement for preprocessor macros and custom
code generators, and the aforementioned features are not necessary to
achieve this goal.</p>
<h2 data-number="2.5" id="rust-macros-and-syn"><span class="header-section-number">2.5</span> Rust : <a href="https://doc.rust-lang.org/book/ch19-06-macros.html">macros</a> and
<a href="https://docs.rs/syn/latest/syn/"><code class="sourceCode cpp">syn</code></a><a href="#rust-macros-and-syn" class="self-link"></a></h2>
<p>Rust macros are essentially functions receiving a sequence of tokens
as input, and producing another sequence of tokens to be injected. In
Rust terminology, derive macros and attributes-like macros are macros
who accept <em>Rust code</em> as input, and produce Rust code as output.
This is interesting, because since Rust does not have reflection, most
users rely on the crate <code class="sourceCode cpp">syn</code> to parse
the input into an AST.</p>
<p>The <code class="sourceCode cpp">syn</code> crate is of interest to
us, as it gives an example of what kind of reflection API is useful in
practice. The <code class="sourceCode cpp">syn</code> API (like our
previous design) is based on 4 sum types :
<code class="sourceCode cpp">Expr</code>,
<code class="sourceCode cpp">Type</code>,
<code class="sourceCode cpp">Stmt</code> and
<code class="sourceCode cpp">Item</code> (roughly equivalent to our
<code class="sourceCode cpp">decl</code>). Of course, since
<code class="sourceCode cpp">syn</code> is not part of Rust standard
library, the challenge of accommodating language evolution is not the
same. However, it is remarkable that the
<code class="sourceCode cpp">syn</code> API had little breaking changes
over the years, relatively to the speed at which Rust evolved.</p>
<p>Another point of interest is <a href="https://lib.rs/crates/syn/rev">how
<code class="sourceCode cpp">syn</code> is used</a> : it’s a
<em>direct</em> dependency in 6% of the crates on crates.io (the Rust
package manager), but it’s a <em>transitive</em> dependency of 59% of
them! In other words, a large proportion of code relies on comparatively
few tools written with it (it’s even used in the rustc compiler), but
most of Rust code does not use it directly.</p>
<p>We expect meta-programming in C++ to be used in a similar manner : a
tool with which is built few but widely used software components, be
they code-generating functionalities (e.g. operators generation,
language bindings generation) or “plain” generic functionalities
(e.g. automatic serialisation/traversal, aggregate formatting,
enum-to-string).</p>
<p>To get back to the claim made in P2996 that changing a typed
reflection API would be impossible (from the amount of work needed to
update its dependents), we think that the way
<code class="sourceCode cpp">syn</code> is used and has evolved paints a
different picture.</p>
<h1 data-number="3" id="reflection"><span class="header-section-number">3</span> Reflection<a href="#reflection" class="self-link"></a></h1>
<p>The reflection operator
<code class="sourceCode cpp"><span class="op">^</span></code> transform
a construct of the language into a value. The operand of the reflection
operator can be a type, expression, declaration, or the global
namespace. The syntax of a <em>reflection-expression</em> is as follows
:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><em>reflection-expression</em> : </span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  ^ ( <em>expression</em> )</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  ^ <em>type-id</em></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  ^ <em>id-expression</em></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  ^ <em>nested-name-specifier<sub>opt</sub></em> <em>namespace-name</em></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  ^ <em>nested-name-specifier<sub>opt</sub></em> <em>template-name</em></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  ^ ::</span></code></pre></div>
<p>The type of the reflection expression is determined by its operand.
The result can be either <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>type</code>,
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>expr</code>,
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>decl</code>,
or <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>overload_set</code>
(which is a range of <code class="sourceCode cpp">decl</code>).</p>
<p>Example :</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> x, y;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>expr e <span class="op">=</span> <span class="op">^(</span>x <span class="op">+</span> y<span class="op">)</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>type t <span class="op">=</span> <span class="op">^</span><span class="dt">int</span><span class="op">[</span><span class="dv">101</span><span class="op">]</span>;</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>decl d <span class="op">=</span> <span class="op">^</span>x;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>overload_set os <span class="op">=</span> <span class="op">^</span><span class="kw">operator</span><span class="op">&lt;</span>; <span class="co">// a range of std::meta::decl</span></span></code></pre></div>
<p>Furthermore, the equality operator is defined for all reflection
types. Its semantics will be defined in the following sections.</p>
<h2 data-number="3.1" id="types"><span class="header-section-number">3.1</span> Types<a href="#types" class="self-link"></a></h2>
<p>A reflected type is a value of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>type</code>.
Types are equality comparable. Implementations are free to preserve
aliases (and perhaps required to do so to a reasonable degree), but
equality comparison shall compare the canonical types.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyInt <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span> <span class="op">^</span>MyInt <span class="op">==</span> <span class="op">^</span><span class="dt">int</span> <span class="op">)</span>;</span></code></pre></div>
<h3 data-number="3.1.1" id="basic-type-manipulation"><span class="header-section-number">3.1.1</span> Basic type manipulation<a href="#basic-type-manipulation" class="self-link"></a></h3>
<p>The
<code class="sourceCode cpp">std<span class="op">::</span>meta</code>
namespace provides a set of functions which cover the functionalities of
<code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>.
These functions have the same name and behavior as their template
counterpart. Obviously, some of the traits in <code class="sourceCode cpp"><span class="op">&lt;</span>type_traits<span class="op">&gt;</span></code>
like <code class="sourceCode cpp">is_same</code> or
<code class="sourceCode cpp">enable_if</code> are not needed.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">// std::meta</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_integral<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_floating_point<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_array<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">// ... </span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_constructible<span class="op">(</span>type t, type_list tl<span class="op">)</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_copy_constructible<span class="op">(</span>type t<span class="op">)</span>; </span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="co">// ...</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type remove_reference<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type add_lvalue_reference<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type remove_pointer<span class="op">(</span>type t<span class="op">)</span>; </span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type add_pointer<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">// ...</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type decay<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type remove_cv_ref<span class="op">(</span>type t<span class="op">)</span>;</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="co">// ...</span></span></code></pre></div>
<h3 data-number="3.1.2" id="template-type-queries"><span class="header-section-number">3.1.2</span> Template type queries<a href="#template-type-queries" class="self-link"></a></h3>
<p>A pretty common need is to inspect the content of template types. For
example, we often want to constrains a function to only accept instance
of a template. The function <code class="sourceCode cpp">is_instance_of<span class="op">(</span>type t, decl d<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span></code>
helps us do that :</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">((</span>is_instance_of<span class="op">(</span>remove_reference<span class="op">(^</span>Ts<span class="op">)</span>, <span class="op">^</span>tuple<span class="op">))</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> tuple_cat<span class="op">(</span>Ts<span class="op">&amp;&amp;...</span> tpls<span class="op">)</span>;</span></code></pre></div>
<p>We can use the function <code class="sourceCode cpp">template_of<span class="op">(</span>type t<span class="op">)</span> <span class="op">-&gt;</span> decl</code>
to the same end :</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, <span class="dt">int</span> N<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span>template_of<span class="op">(</span>remove_reference<span class="op">(^</span>T<span class="op">))</span> <span class="op">==</span> <span class="op">^</span>tuple<span class="op">)</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span><span class="op">&amp;&amp;</span> get<span class="op">(</span>T<span class="op">&amp;&amp;</span> tpl<span class="op">)</span>;</span></code></pre></div>
<p>We can also query template arguments, which is a necessary facility
to the implementation of <code class="sourceCode cpp">tuple_cat</code>
:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>meta;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> tuple_cat_result_type<span class="op">(</span>type_list tl<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  template_argument_list args;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> t <span class="op">:</span> tl<span class="op">)</span> </span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> a <span class="op">:</span> template_arguments_of<span class="op">(</span>t<span class="op">))</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>      push_back<span class="op">(</span>args, a<span class="op">)</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>tuple, args<span class="op">)</span>;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Here the function <code class="sourceCode cpp">substitute</code>
expand the argument list into <code class="sourceCode cpp">tuple</code>.
An evaluation error is produced if substitution fails. However, the
instantiation of the definition is done upon use.</p>
<h3 data-number="3.1.3" id="conversion-to-declaration"><span class="header-section-number">3.1.3</span> Conversion to declaration<a href="#conversion-to-declaration" class="self-link"></a></h3>
<p>Some types, like enumeration, class, and class template types have a
corresponding declaration, which can be accessed through
<code class="sourceCode cpp">decl_of</code> :</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_or_contains_pointer<span class="op">(</span>type t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>is_pointer<span class="op">(</span>t<span class="op">))</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(!</span>is_class<span class="op">(</span>t<span class="op">))</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> fields<span class="op">(</span>decl_of<span class="op">(</span>t<span class="op">)))</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>is_pointer<span class="op">(</span>type_of<span class="op">(</span>f<span class="op">)))</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>(we will talk about the function
<code class="sourceCode cpp">fields</code> in the next chapter)</p>
<h3 data-number="3.1.4" id="hashing"><span class="header-section-number">3.1.4</span> Hashing<a href="#hashing" class="self-link"></a></h3>
<p>We propose that a <code class="sourceCode cpp">hash</code> function
shall be defined for types, but we’re not quite sure if the value
produced should be stable across invocations of the compiler. In our
current implementation, it isn’t.</p>
<h3 data-number="3.1.5" id="comparison-to-p2996"><span class="header-section-number">3.1.5</span> Comparison to P2996<a href="#comparison-to-p2996" class="self-link"></a></h3>
<p>Here is the <code class="sourceCode cpp">tuple_cat_result_type</code>
function written with P2996 :</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info tuple_cat_result_type<span class="op">(</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> tl<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> args;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> t <span class="op">:</span> tl<span class="op">)</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    args<span class="op">.</span>append_range<span class="op">(</span>template_arguments_of<span class="op">(</span>t<span class="op">))</span>;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> substitute<span class="op">(^</span>tuple, args<span class="op">)</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We’ve already talked about the pros and cons of using compiler
builtins types vs
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>,
but clearly, having the
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
interface is an ergonomic advantage over the rather spartan interface
that our builtins types provide, and it would be the ideal solution if
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
could be structural.</p>
<h2 data-number="3.2" id="declarations"><span class="header-section-number">3.2</span> Declarations<a href="#declarations" class="self-link"></a></h2>
<p>We propose a set of queries related to declarations that should be
enough to power most meta-programming applications. Those are the
functionalities over declarations we needed to achieve our use-cases
:</p>
<ul>
<li>query their name</li>
<li>query their members + (convenience functions for instance data
members/functions…)</li>
<li>query their kind (class/function/namespace/data member…)</li>
<li>query their type</li>
<li>if classes, query their bases classes</li>
<li>lookup a member</li>
<li>if function, query their parameters</li>
<li>if enumerator, query their underlying values</li>
<li>query their default value (for data member, function parameter)</li>
</ul>
<p>Those functionalities are covered by the following functions :</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co">// name</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> name name_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> identifier identifier_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="co">// members</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list children<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> field_list fields<span class="op">(</span>decl d<span class="op">)</span>; <span class="co">// the instance data members of d, if d is a class, in a random-access range</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list functions<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list enumerators<span class="op">(</span>decl d<span class="op">)</span>; </span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="co">// kind </span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_function<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_class<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_namespace<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_variable<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_enum<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a><span class="co">// ... ect</span></span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type type_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-20"><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> base_class_list bases_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-21"><a href="#cb10-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-22"><a href="#cb10-22" aria-hidden="true" tabindex="-1"></a><span class="co">// lookup a member </span></span>
<span id="cb10-23"><a href="#cb10-23" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list lookup<span class="op">(</span>decl d, name n<span class="op">)</span>; <span class="co">// (this lookup looks at members of base classes if d is a class)</span></span>
<span id="cb10-24"><a href="#cb10-24" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list lookup_excluding_bases<span class="op">(</span>decl d, name n<span class="op">)</span>;</span>
<span id="cb10-25"><a href="#cb10-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-26"><a href="#cb10-26" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list parameters_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-27"><a href="#cb10-27" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> decl_list template_parameters_of<span class="op">(</span>decl d<span class="op">)</span>;</span>
<span id="cb10-28"><a href="#cb10-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-29"><a href="#cb10-29" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr initializer<span class="op">(</span>decl d<span class="op">)</span>; <span class="co">// initializer if variable, default value if data member or parameter </span></span>
<span id="cb10-30"><a href="#cb10-30" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr underlying_value<span class="op">(</span>decl d<span class="op">)</span>; <span class="co">// underlying value if enum constant</span></span></code></pre></div>
<p>We propose that template instances can be
<code class="sourceCode cpp">decl</code>s and shall be represented as
template specialisations declarations – so that their data members can
be reflected just like a class, for example.</p>
<p>There are some questions surrounding declarations reflection that we
haven’t fully resolved yet : we are not quite sure how to handle
using-directives or using-declarations, whether or not implicitly
declared members should be visible on traversal, or if querying the name
of an anonymous declaration should produce an evaluation error or an
empty identifier.</p>
<h3 data-number="3.2.1" id="declaration-name"><span class="header-section-number">3.2.1</span> Declaration name<a href="#declaration-name" class="self-link"></a></h3>
<p>The function <code class="sourceCode cpp">name_of</code> returns a
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>name</code>,
unlike P2996 which returns a <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>.
Returning a string_view is fine for the uses that P2996 demonstrate. In
our case, it’s a bit awkward, especially when dealing with operators and
conversion names : we might want to inject an operator which depends on
the name of a function (see meta-programming : expressions), or obtains
the type of the conversion name, which we can’t do from a string view.
We also don’t want to have to parse the string ourselves to know which
kind of name we have.</p>
<p>In the proposed API, a <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>name</code>
can be an identifier, an operator, a conversion type, or the name of a
special member function. We have a separate type to represents
identifiers, <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>identifier</code>.
Furthermore, an enumeration type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>operator_kind</code>
is provided to represents operators.</p>
<p>We consider the name of special member functions to be class
independent, that is, <code class="sourceCode cpp">name_of<span class="op">(^</span>Struct1<span class="op">::</span>Struct1<span class="op">)</span> <span class="op">==</span> name_of<span class="op">(^</span>Struct2<span class="op">::</span>Struct2<span class="op">)</span></code>.</p>
<p>A set of predicates over <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>name</code>
is provided :</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">// namespace std::meta</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_identifier<span class="op">(</span>name n<span class="op">)</span>;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_operator<span class="op">(</span>name n<span class="op">)</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_conversion<span class="op">(</span>name n<span class="op">)</span>;</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_constructor<span class="op">(</span>name n<span class="op">)</span>;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> is_destructor<span class="op">(</span>name n<span class="op">)</span>;</span></code></pre></div>
<p>To retrieve the identifier, operator, or conversion type,
<code class="sourceCode cpp">name</code> can be cast to its subtypes
:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>name n <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> op <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span>operator_kind<span class="op">&gt;(</span>n<span class="op">)</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> id <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span>identifier<span class="op">&gt;(</span>n<span class="op">)</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> ty <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span>type<span class="op">&gt;(</span>n<span class="op">)</span>;</span></code></pre></div>
<p>The evaluation of these casts errors out if the name is not an
operator, identifier or type conversion, respectively.</p>
<h3 data-number="3.2.2" id="object-parameter"><span class="header-section-number">3.2.2</span> Object parameter<a href="#object-parameter" class="self-link"></a></h3>
<p>Should the object parameter, even if implicit, be included in the
range returned by the <code class="sourceCode cpp">parameters_of</code>
query? We’re inclined to say yes (we treat the implicit object parameter
as an anonymous declaration). At the very least, the answer should not
change depending on its explicitness, which would be weird. But there
are cases where we are only interested in the “inner” parameters, and to
that end we provide a function
<code class="sourceCode cpp">inner_parameters_of</code>.</p>
<h2 data-number="3.3" id="expressions"><span class="header-section-number">3.3</span> Expressions<a href="#expressions" class="self-link"></a></h2>
<p>For now we do not propose any queries related to expressions beyond
<code class="sourceCode cpp">type_of</code>,
<code class="sourceCode cpp">location</code>, and maybe a
<code class="sourceCode cpp">hash</code> function (see enum-to-string
use case).</p>
<p>Equality comparison of expressions test the equivalence of two
expressions. Parens within the expression are ignored.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span> <span class="op">^(</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">)</span> <span class="op">==</span> <span class="op">^((</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">))</span> <span class="op">)</span>;</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span> <span class="op">^(</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">)</span> <span class="op">!=</span> <span class="op">^(</span><span class="dv">2</span> <span class="op">+</span> <span class="dv">1</span><span class="op">)</span> <span class="op">)</span>;</span></code></pre></div>
<p>For convenience, a reflection of a list of comma separated
expressions gives an <code class="sourceCode cpp">expr_list</code>
(instead of a relatively uninteresting comma-expression).</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>expr_list e <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="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr tuple_cat_gen<span class="op">(</span>expr_list el<span class="op">)</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> tuple_cat<span class="op">(</span>Ts<span class="op">...</span> tpls<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> result <span class="op">=</span> tuple_cat_gen<span class="op">(</span> <span class="op">^(</span>tpls<span class="op">...)</span> <span class="op">)</span>; <span class="co">// also construct an expr_list</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Some functions which construct expressions will be covered in the
meta-programming part.</p>
<h2 data-number="3.4" id="conversion-to-text-and-diagnosis"><span class="header-section-number">3.4</span> Conversion to text and
diagnosis<a href="#conversion-to-text-and-diagnosis" class="self-link"></a></h2>
<p>Conversion to text is often needed by meta-programs, and it has been
a necessity in a good proportion of our use cases. To this end we
propose a general purpose mechanism to build chain of characters from
builtins and reflection typed values : <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>stringstream</code>.
It behaves essentially like <code class="sourceCode cpp">std<span class="op">::</span>stringstream</code>
:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>stringstream os;</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>os <span class="op">&lt;&lt;</span> <span class="st">&quot;hello &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">^(</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">)</span> <span class="op">&lt;&lt;</span> <span class="st">&quot; &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">^</span>std<span class="op">::</span>meta <span class="op">&lt;&lt;</span> <span class="st">&quot; &quot;</span> <span class="op">&lt;&lt;</span> <span class="op">^</span><span class="dt">int</span><span class="op">[</span><span class="dv">121</span><span class="op">]</span> <span class="op">&lt;&lt;</span> <span class="st">&quot; &quot;</span> <span class="op">&lt;&lt;</span> name_of<span class="op">(^</span>os<span class="op">)</span>; </span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co">// the content of the stream is now &quot;hello 1 + 2 std::meta int[121] os&quot;  </span></span></code></pre></div>
<p>Its content can be used in three ways. First,
<code class="sourceCode cpp">begin</code> and
<code class="sourceCode cpp">end</code> yield iterators over the content
of the stream, returning a
<code class="sourceCode cpp"><span class="dt">char</span></code>
pr-value.</p>
<p>Second, the function
<code class="sourceCode cpp">make_literal_expr</code> takes a stream as
argument to construct a string literal expression (see use cases
enum-to-string and class registration).</p>
<p>Finally, it can be used to emit diagnostics. Emitting user-friendly
diagnostics is needed as we expect a lot of meta-programming code to
come with pre-conditions, which, if not fulfilled, will result in
failure at the point of injection.</p>
<p>The following intrinsics can be used to emit diagnostics :</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> DiagMsg <span class="op">=</span> <span class="op">^</span>T <span class="op">==</span> <span class="op">^</span>std<span class="op">::</span>meta<span class="op">::</span>stringstream <span class="op">||</span> <span class="op">^</span>T <span class="op">==</span> <span class="op">^</span><span class="kw">const</span> <span class="dt">char</span><span class="op">*</span>;</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> ensure<span class="op">(</span><span class="dt">bool</span> b<span class="op">)</span>; <span class="co">// compile-time assertion</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> ensure<span class="op">(</span>source_location loc, <span class="dt">bool</span> b<span class="op">)</span>; <span class="co">// ditto, but emit an error at loc </span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> error<span class="op">(</span><span class="kw">const</span> DiagMsg <span class="kw">auto</span><span class="op">&amp;</span> s<span class="op">)</span>; </span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> error<span class="op">(</span>source_location loc, <span class="kw">const</span> DiagMsg <span class="kw">auto</span><span class="op">&amp;</span> s<span class="op">)</span>;</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> warning<span class="op">(</span><span class="kw">const</span> DiagMsg <span class="kw">auto</span><span class="op">&amp;</span> s<span class="op">)</span>;</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> warning<span class="op">(</span>source_location loc, <span class="kw">const</span> DiagMsg <span class="kw">auto</span><span class="op">&amp;</span> s<span class="op">)</span>;</span></code></pre></div>
<p>Furthermore, we propose to constexpr-ise
<code class="sourceCode cpp">std<span class="op">::</span>format</code>,
and that the <code class="sourceCode cpp"><span class="op">&lt;</span>format<span class="op">&gt;</span></code>
header provides the following functions :</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">// namespace std::meta</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Str, <span class="kw">class</span> Args<span class="op">&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> error<span class="op">(</span>Str<span class="op">&amp;&amp;</span> str, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>; </span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="co">// implemented as </span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="co">// error( std::format(str, static_cast&lt;Args&amp;&amp;&gt;(args)...).c_str() );</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Str, <span class="kw">class</span> Args<span class="op">&gt;</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> error<span class="op">(</span>source_location loc, Str<span class="op">&amp;&amp;</span> str, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Str, <span class="kw">class</span> Args<span class="op">&gt;</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> warning<span class="op">(</span>Str<span class="op">&amp;&amp;</span> str, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Str, <span class="kw">class</span> Args<span class="op">&gt;</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> warning<span class="op">(</span>source_location loc, Str<span class="op">&amp;&amp;</span> str, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>A specialisation of <code class="sourceCode cpp">std<span class="op">::</span>formatter</code>
exists for all reflection types (which is quite straightforward to
implement with <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>stringstream</code>).</p>
<h2 data-number="3.5" id="syntax-issues-the-caret-and-objective-c"><span class="header-section-number">3.5</span> Syntax issues : the caret and
Objective-C<a href="#syntax-issues-the-caret-and-objective-c" class="self-link"></a></h2>
<p>As noted by <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3381r0.html">P3381</a>,
using the caret as the reflection operator causes a conflict with the
following Objective-C syntax :</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><em>type-id</em>(^ident)();</span></code></pre></div>
<p>which can be parsed as either :</p>
<ul>
<li>a variable named ident holding a Obj-C block returning type-id and
taking no arguments, and</li>
<li>a cast of a reflection of <code class="sourceCode cpp">ident</code>
into a type-id and then a call of operator()</li>
</ul>
<p>The authors therefore propose to change
<code class="sourceCode cpp"><span class="op">^</span></code> to
<code class="sourceCode cpp"><span class="op">^^</span></code>.</p>
<p>While this is a problem, we contend that the conflict could be worked
around. We think that this syntax pattern has a rather low chance of
being used for reflection purpose, and that few people would be
negatively impacted by a compiler interpreting this pattern as an
Objective-C declaration, especially if they deliberately compile with
Objective-C blocks extension enabled (and if an user intends the second
meaning, this expression can be easily rewritten non-ambiguously).</p>
<p>Furthermore, our prototype already use the token
<code class="sourceCode cpp"><span class="op">^^</span></code> for the
“eager” reflection operator (a reflection operator who is never
dependent, i.e. can be used to reflect on dependent entities prior to
template substitution). This is a rather advanced topic that we won’t
talk about here, but it’s another motivation for us to try to find a
compromise and keep
<code class="sourceCode cpp"><span class="op">^</span></code>.</p>
<p>The second issue pointed by P3381 is not a problem for us (see the
next section).</p>
<h1 data-number="4" id="meta-programming"><span class="header-section-number">4</span> Meta-programming<a href="#meta-programming" class="self-link"></a></h1>
<p>To begin with the syntax, we’ve chosen a prefix
<code class="sourceCode cpp"><span class="op">%</span></code> as the
injection operator.</p>
<p>It can be used to inject types and expressions, or to introduce an
injection statement.</p>
<p>Injection statements inject <em>code fragments</em>. Fragments are
pieces of code that can be parametrised by explicitly captured values.
Those captured values are akin to template parameters : they are
constant expressions when referenced from inside the fragment.</p>
<p>Substitution of the fragment is performed <em>on injection</em>. The
captures values are initialised when evaluating the fragment expression,
and destroyed after injection is done.</p>
<p>Code fragments are used with <em>builders</em>. A builder is an
handle to a language entity being constructed, it comes from an
injection statement, which can appear at function, class, namespace, or
enum scope.</p>
<p>An injection statement looks like this :</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span>inject_something<span class="op">()</span>;</span></code></pre></div>
<p>It can appears, at function, class, namespace or enumeration scope.
If the injection operand is a call-expression, the callee receives a
reference to a <em>builder</em> as first argument. This builder is typed
according to the scope enclosing the injection statement (either
<code class="sourceCode cpp">function_builder</code>,
<code class="sourceCode cpp">class_builder</code>,
<code class="sourceCode cpp">namespace_builder</code>, or
<code class="sourceCode cpp">enum_builder</code>).</p>
<p>A builder can be used to inject code via <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;&lt;</span></code>,
the right-hand-side must be suitably typed (see below). It also gives
access to the declaration behind constructed via the
<code class="sourceCode cpp">decl_of</code> function, and the injection
location via <code class="sourceCode cpp">location</code>.</p>
<p>If the type of the injection operand is not void, it will be injected
(and thus must be convertible to the fragment type associated with the
context).</p>
<p>Injections statements can also appears in fragments, in which case
they will be evaluated upon injection of the fragment.</p>
<p>The syntax of fragments and parametrised expression is as follows
:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><em>parametrised-expression</em> <span class="op">:</span> </span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">^</span> <span class="op">[</span><em>captures</em><span class="op">]</span> <span class="op">(</span> <em>expression</em> <span class="op">)</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><em>function-fragment</em> <span class="op">:</span> </span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">^</span> <span class="op">[</span><em>captures</em><span class="op">]</span> <span class="op">{</span> <em>statement</em> <span class="op">}</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><em>class-fragment</em> <span class="op">:</span> </span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">^</span> <span class="op">[</span><em>captures</em><span class="op">]</span><sub><em>opt</em></sub> <span class="kw">struct</span> <span class="op">{</span> <em>member-specification</em> <span class="op">}</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a><em>namespace-fragment</em> <span class="op">:</span> </span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">^</span> <span class="op">[</span><em>captures</em><span class="op">]</span><sub><em>opt</em></sub> <span class="kw">namespace</span> <span class="op">{</span> <em>namespace-body</em> <span class="op">}</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a><em>enum-fragment</em> <span class="op">:</span> </span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">^</span> <span class="op">[</span><em>captures</em><span class="op">]</span><sub><em>opt</em></sub> <span class="kw">enum</span> <span class="op">{</span> <em>enumerator-list</em> <span class="op">}</span></span></code></pre></div>
<p>The types of these expressions are
<code class="sourceCode cpp">expr</code>,
<code class="sourceCode cpp">function_fragment</code>,
<code class="sourceCode cpp">class_fragment</code>,
<code class="sourceCode cpp">namespace_fragment</code>, and
<code class="sourceCode cpp">enum_fragment</code>, respectively.</p>
<p>As previously stated, expressions and types can also be injected. The
syntax</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span> <em>constant-expression</em></span></code></pre></div>
<p>inject a type or expression depending on the context in which it
appears. The type of the operand must be
<code class="sourceCode cpp">type</code> or
<code class="sourceCode cpp">expr</code>. In the declarator context,
disambiguation is required to introduce an injected type. The following
syntax must be used to inject a type in a function prototype, variable
or data member declarator.</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span> <span class="kw">typename</span> <span class="op">(</span> <em>constant-expression</em> <span class="op">)</span></span></code></pre></div>
<h2 data-number="4.1" id="expressions-1"><span class="header-section-number">4.1</span> Expressions<a href="#expressions-1" class="self-link"></a></h2>
<p>The primary way to construct expressions is using parametrised
expressions. We don’t call them fragments, because unlike fragments,
substitution is performed when the <em>parametrised-expression</em>
expression is encountered.</p>
<p>For example :</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr make_add<span class="op">(</span>expr l, expr r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>l, r<span class="op">]</span> <span class="op">(%</span>l <span class="op">+</span> <span class="op">%</span>r<span class="op">)</span>;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr lift<span class="op">(</span>overload_set os<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>os<span class="op">]</span> <span class="op">(</span> <span class="op">[]</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">(%</span>os<span class="op">)(</span>args<span class="op">...)</span>; <span class="op">}</span> <span class="op">)</span>;</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>There is a few things that plain substitution of expression does not
do well, at least not without further extension of the language. For
example, the operators generation use case depends on being able to
construct an operator expression from a <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>operator_kind</code>.</p>
<p>We’ve been thinking of implementing operator injection with the
following syntax :</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr make_operator_expr<span class="op">(</span>operator_kind op, expr l, expr r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^[</span>op, l, r<span class="op">]</span> <span class="op">(</span> <span class="op">%</span><span class="kw">operator</span><span class="op">(</span>op<span class="op">)(%</span>l, <span class="op">%</span>r<span class="op">)</span> <span class="op">)</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>But for now, we are simply providing a
<code class="sourceCode cpp">make_operator_expr</code> function which
does exactly that.</p>
<h3 data-number="4.1.1" id="expression-pack-injection"><span class="header-section-number">4.1.1</span> Expression pack injection<a href="#expression-pack-injection" class="self-link"></a></h3>
<p>Another thing that substitution needs is the ability to expand
ranges. For example, given a range of expressions, we want to be able to
expand it into an argument list to make a call expression :</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr make_call_expr<span class="op">(</span>expr callee, expr_list args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^[</span>callee, args<span class="op">]</span> <span class="op">(</span> <span class="op">(%</span>callee<span class="op">)(%...</span>args<span class="op">...)</span>;</span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The syntax</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span> <span class="op">...</span> <em>constant-expression</em></span></code></pre></div>
<p>creates a <em>pack-injection expression</em>. This expression
contains an unexpanded parameter pack whose elements results from the
constant evaluation of the injection operand, which in this case must be
convertible to <code class="sourceCode cpp">expr_list</code>. It behaves
just like a parameter pack would, and can be used along template
parameters pack, in fold expressions, etc.</p>
<p>So in the above example,
<code class="sourceCode cpp"><span class="op">%...</span>args</code>
creates an unexpanded pack, and the following ellipsis expand it into
the argument list.</p>
<p>Pack injection can happen with a non-dependent operand, in which case
the expansion is done immediately :</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> args <span class="op">=</span> <span class="op">^(</span>lots, of, arguments<span class="op">)</span>;</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> foo<span class="op">(%...</span>args<span class="op">...</span>, <span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span> <span class="op">+</span> bar<span class="op">(%...</span>args<span class="op">...)</span>;</span></code></pre></div>
<h3 data-number="4.1.2" id="member-injection-expression"><span class="header-section-number">4.1.2</span> Member injection expression<a href="#member-injection-expression" class="self-link"></a></h3>
<p>The syntax</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><em>expression</em> <span class="op">.%(</span> <em>constant-expression</em> <span class="op">)</span></span></code></pre></div>
<p>creates a <em>member injection expression</em>. The injection operand
must be convertible to either <code class="sourceCode cpp">decl</code>
or <code class="sourceCode cpp">name</code>.</p>
<p>For example, here is an implementation of
<code class="sourceCode cpp">get</code> for tuple, assuming data members
named <code class="sourceCode cpp">mX</code> :</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">int</span> N, <span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span><span class="op">&amp;</span> get<span class="op">(</span>tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&amp;</span> t<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> t<span class="op">.%(</span>cat<span class="op">(</span><span class="st">&quot;m&quot;</span>, N<span class="op">))</span>; <span class="op">}</span></span></code></pre></div>
<h2 data-number="4.2" id="function-fragments"><span class="header-section-number">4.2</span> Function fragments<a href="#function-fragments" class="self-link"></a></h2>
<p>Function fragments are a sequence of statements, optionally
parametrised by captures values. Within a function fragment, the return
type is treated as dependent. Statements whose validity depends on the
presence of an enclosing scope, such as break, continue, or case
statements, can be used – an error will be emitted upon injection if
their use is invalid in the injection scope.</p>
<p>The capture list must appear even if empty, to disambiguate against
Objective-C blocks.</p>
<p>To illustrate, here is an implementation of an enum-to-string
function :</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_enum_to_string<span class="op">(</span>function_builder<span class="op">&amp;</span> b, decl Enum<span class="op">)</span> </span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> enumerator <span class="op">:</span> children<span class="op">(</span>Enum<span class="op">))</span></span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>meta<span class="op">::</span>stringstream ss;</span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a>    ss <span class="op">&lt;&lt;</span> name_of<span class="op">(</span>enumerator<span class="op">)</span>;</span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^[</span>enumerator, lit <span class="op">=</span> make_literal_expr<span class="op">(</span>ss<span class="op">)]</span> <span class="op">{</span></span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a>      <span class="cf">case</span> <span class="op">%</span>enumerator <span class="op">:</span> <span class="cf">return</span> <span class="op">%</span>lit;</span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> E<span class="op">&gt;</span></span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span>is_enum<span class="op">(^</span>E<span class="op">))</span></span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">const</span> <span class="dt">char</span><span class="op">*</span> to_string<span class="op">(</span>E e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a>  <span class="cf">switch</span><span class="op">(</span>e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">%</span>gen_enum_to_string<span class="op">(^</span>E<span class="op">)</span>;</span>
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.3" id="injection-of-names"><span class="header-section-number">4.3</span> Injection of names<a href="#injection-of-names" class="self-link"></a></h2>
<p>To generate an arbitrarily named declaration, we must be able to
inject names. To this end, we propose that the syntax</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span> name <span class="op">(</span> <em>constant-expression</em> <span class="op">)</span></span></code></pre></div>
<p>shall produce an injected name, which can appear in the place of a
<em>declarator-id</em>, <em>class-name</em>, <em>enum-name</em>, or
<em>enumerator</em>.</p>
<p>The injection operand must be of the type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>name</code>.</p>
<p>If the injected name is illegal for the declaration for which it is
intended (e.g. if it is an operator name for a variable declaration), an
error is emitted. Furthermore, constructors cannot be declared with an
injected name.</p>
<p>Note that injected names are for <em>declaration purpose only</em>,
they cannot be used for looking up an existing entity.</p>
<h2 data-number="4.4" id="namespace-fragments"><span class="header-section-number">4.4</span> Namespace fragments<a href="#namespace-fragments" class="self-link"></a></h2>
<p>Namespace fragments are a sequence of namespace members potentially
parametrised by captures values.</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> inject_stuff<span class="op">(</span>namespace_builder<span class="op">&amp;</span> b, <span class="dt">int</span> k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>k<span class="op">]</span> <span class="kw">namespace</span> <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> f<span class="op">()</span>;</span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> <span class="op">%</span>name<span class="op">(</span>cat<span class="op">(</span><span class="st">&quot;f&quot;</span>, k<span class="op">))</span> <span class="op">()</span>;</span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In this example, the injection statement <code class="sourceCode cpp"><span class="op">%</span>inject_stuff<span class="op">(</span><span class="dv">101</span><span class="op">)</span></code>
will produce the functions <code class="sourceCode cpp">f</code> and
<code class="sourceCode cpp">f101</code>.</p>
<h2 data-number="4.5" id="enum-fragments"><span class="header-section-number">4.5</span> Enum fragments<a href="#enum-fragments" class="self-link"></a></h2>
<p>Enum fragments are a sequence of enumerators (or injections
statements) potentially parametrised by captures values.</p>
<p>As an example, here is a simple function which generates a sequence
of enumerators suitable for using the enum as a sum of flags :</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_flagsum<span class="op">(</span>enum_builder<span class="op">&amp;</span> b, <span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>identifier<span class="op">&gt;&amp;</span> ids<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> k <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> id <span class="op">:</span> ids<span class="op">)</span></span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>id, k<span class="op">]</span> <span class="kw">enum</span> <span class="op">{</span> <span class="op">%</span>name<span class="op">(</span>id<span class="op">)</span> <span class="op">=</span> k <span class="op">}</span>;</span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a>    k <span class="op">*=</span> <span class="dv">2</span>;</span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> MyEnum <span class="op">{</span></span>
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">%</span>gen_flagsum<span class="op">({</span><span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;c&quot;</span><span class="op">})</span></span>
<span id="cb33-12"><a href="#cb33-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="4.6" id="class-fragments"><span class="header-section-number">4.6</span> Class fragments<a href="#class-fragments" class="self-link"></a></h2>
<p>A class fragment is a sequence of member declarations potentially
parametrised by capture values. In a class fragment, the type of
<code class="sourceCode cpp"><span class="kw">this</span></code> is
dependent. This naturally allows for two-phase lookup at the point of
injection :</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> postfix_increment <span class="op">=</span> <span class="op">^</span> <span class="kw">struct</span> </span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">++(</span><span class="dt">int</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> tmp <span class="op">=</span> <span class="op">*</span><span class="kw">this</span>;</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">++</span>tmp;</span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> tmp;</span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Andrew Sutton in P2237 touches upon the problem of declaring
constructors within a fragment or referencing the class in which we will
be injecting. We propose the same solution as Sutton : class fragments
can be named, and that a reference to this name shall be substituted
upon injection.</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> inject_stuff<span class="op">(</span>class_builder<span class="op">&amp;</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="kw">struct</span> T <span class="op">{</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// declaring constructors/destructors</span></span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>    T<span class="op">()</span> <span class="op">{...}</span></span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">~</span>T<span class="op">()</span> <span class="op">{...}</span> </span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// referencing the destination type </span></span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> T<span class="op">&amp;</span> o<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The injection of the member functions bodies is done only when the
class in which the injection is performed has been completed. This
forbids using captures that contains references to local values in the
bodies of member functions, as the evaluation context at that point will
be gone.</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr gen_eq<span class="op">(</span>expr l, expr r, R<span class="op">&amp;&amp;</span> members<span class="op">)</span> <span class="op">{</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>  expr res <span class="op">=</span> <span class="op">^(</span><span class="kw">true</span><span class="op">)</span>;</span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> m <span class="op">:</span> members<span class="op">)</span></span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>    res <span class="op">=</span> <span class="op">^</span> <span class="op">[</span>res, m, l, r<span class="op">]</span> <span class="op">(</span> res <span class="op">&amp;&amp;</span> <span class="op">((%</span>l<span class="op">).%(</span>m<span class="op">)</span> <span class="op">==</span> <span class="op">(%</span>r<span class="op">).%(</span>m<span class="op">))</span> <span class="op">)</span>;</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> res;</span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> eq_according_to<span class="op">(</span>class_builder<span class="op">&amp;</span> b, std<span class="op">::</span>vector<span class="op">&lt;</span>decl<span class="op">&gt;</span> members<span class="op">)</span> <span class="op">{</span></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>span<span class="op">&lt;</span><span class="kw">const</span> decl<span class="op">&gt;</span> members_span <span class="op">{</span>members<span class="op">.</span>begin<span class="op">()</span>, members<span class="op">.</span>end<span class="op">()}</span>; <span class="co">// naively trying to avoid a copy...</span></span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>members_span<span class="op">]</span> <span class="kw">struct</span> T <span class="op">{</span></span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> T<span class="op">&amp;</span> o<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span>gen_eq<span class="op">(^(*</span><span class="kw">this</span><span class="op">)</span>, <span class="op">^(</span>o<span class="op">)</span>, members_span<span class="op">)</span>;</span>
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In this example, the evaluation of the injection operand in <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">==</span></code>
will errors out as we attempt to read out-of-lifetime values. The
solution is to simply capture the vector itself.</p>
<h2 data-number="4.7" id="fragment-captures-technicals-considerations"><span class="header-section-number">4.7</span> Fragment captures : technicals
considerations<a href="#fragment-captures-technicals-considerations" class="self-link"></a></h2>
<p>What kind of values can be used as fragments captures? This is a
complex question.</p>
<p>It depends on <em>how</em> the capture is used. Some use will
requires it to be substituted by a perennial, equivalent expression as
in</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> e <span class="op">=</span> <span class="op">^</span> <span class="op">[</span>k <span class="op">=</span> <span class="dv">101</span><span class="op">]</span> <span class="op">(</span>some_function<span class="op">(</span>k<span class="op">))</span>;</span></code></pre></div>
<p>while others does not, as in :</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>decl<span class="op">&gt;</span> vec <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> e <span class="op">=</span> <span class="op">^</span> <span class="op">[</span>vec<span class="op">]</span> <span class="op">(</span> <span class="op">%</span>make_some_expr<span class="op">(</span>vec<span class="op">)</span> <span class="op">)</span>;</span></code></pre></div>
<p>The latter simply reference <code class="sourceCode cpp">vec</code>
in the computation of the inner injection operand, but once that is
done, the expression obtained is that which is produced by
<code class="sourceCode cpp">make_some_expr</code>, so there is no need
to produce an expression equivalent to
<code class="sourceCode cpp">vec</code>. We will call the first kind of
capture use <em>perennial use</em>, and the second kind <em>instant
use</em>.</p>
<p>So what kind of capture can be perennially used? At the very least,
only those of literal types, because a perennial use of a capture of
class type imply declaring a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
global to reference in the substituted expression – and some might want
to say : only structural types, because we want to “unique” them into a
set so that we don’t emit more declarations than we need. Either way,
this precludes the usual dynamic containers.</p>
<p>This is why we’ve kept the compiler builtins types for dynamic
containers : since they are structural (because the elements are
immutable), they can always be used as fragment captures, and as
template arguments.</p>
<p>Class fragments impose yet another constraint. Because the body of
their member functions will be substituted only once the class is
complete, even an <em>instant use</em> of a capture can be problematic
if said capture references local values.</p>
<h3 data-number="4.7.1" id="captures-and-template-definition"><span class="header-section-number">4.7.1</span> Captures and template
definition<a href="#captures-and-template-definition" class="self-link"></a></h3>
<p>The problem of replacing a non-structural value by a perennial
expression is why we cannot, for example, generate the body of a
function template from a
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
at the moment :</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_foo<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span> vec, expr fn<span class="op">)</span>;</span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> inject_stuff<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> vec<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>vec<span class="op">]</span> <span class="kw">namespace</span> </span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> foo<span class="op">(</span>T Fn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span>gen_foo<span class="op">(</span>vec, <span class="op">^(</span>Fn<span class="op">))</span>; <span class="co">// compiler error : instant use fragment capture cannot be part of dependent injection operand</span></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a><span class="op">%</span>inject_stuff<span class="op">({</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>The injection operand <code class="sourceCode cpp">gen_foo<span class="op">(</span>vec, <span class="op">^(</span>Fn<span class="op">))</span></code>
is still value-dependent after fragment injection, and cannot be
evaluated. But we cannot have an expression equivalent to
<code class="sourceCode cpp">vec</code> outside of the fragment
injection context, so the compiler emits an error.</p>
<p>What can be done about this? We’ve been exploring what we call “eager
reflection”, which allow to reflect on entities prior to template
substitution, and would let us generate the body of template using
non-structural values. With eager reflection, <code class="sourceCode cpp"><span class="op">^^(</span>Fn<span class="op">)</span></code>
would the reflection of <code class="sourceCode cpp">Fn</code> prior to
template substitution, and thus would be non-dependent, so the injection
operand can be evaluated on fragment injection.</p>
<h1 data-number="5" id="use-cases"><span class="header-section-number">5</span> Use-cases<a href="#use-cases" class="self-link"></a></h1>
<p>Here is a series of use cases which guided our design. We will make
comparisons to P2996 when applicable.</p>
<h2 data-number="5.1" id="enum-to-string"><span class="header-section-number">5.1</span> Enum to string<a href="#enum-to-string" class="self-link"></a></h2>
<p>We’ve already shown a simple implementation of enum to string in the
function fragments section. However, a complete implementation need to
take into account repeating values, or enumeration used as a sum of
flag. P2996 does the former implicitly by generating a chain of
<code class="sourceCode cpp"><span class="cf">if</span></code>. We could
also do that, but for the sake of exploration, we would like to
implement our function as a single switch.</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_enum_to_string<span class="op">(</span>function_builder<span class="op">&amp;</span> b, decl d<span class="op">)</span> </span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a>  constexpr_map<span class="op">&lt;</span>expr, expr<span class="op">&gt;</span> map;</span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> e <span class="op">:</span> children<span class="op">(</span>d<span class="op">))</span></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a>    map<span class="op">.</span>try_emplace<span class="op">(</span> underlying_value<span class="op">(</span>d<span class="op">)</span>, make_literal_expr<span class="op">(</span>identifier_of<span class="op">(</span>d<span class="op">))</span> <span class="op">)</span>;</span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> m <span class="op">:</span> map<span class="op">)</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>m<span class="op">]</span> <span class="op">{</span></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a>      <span class="cf">case</span> <span class="op">%</span>m<span class="op">.</span>first <span class="op">:</span> <span class="cf">return</span> <span class="op">%</span>m<span class="op">.</span>second;</span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> is_enum<span class="op">(^</span>T<span class="op">)</span></span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>string_view enum_to_string<span class="op">(</span>T val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">switch</span><span class="op">(</span>std<span class="op">::</span>to_underlying<span class="op">(</span>val<span class="op">))</span> <span class="op">{</span></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">%</span>gen_enum_to_string<span class="op">(^</span>T<span class="op">)</span>;</span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">default</span> <span class="op">:</span> <span class="cf">return</span> <span class="st">&quot;&lt;invalid&gt;&quot;</span>;</span>
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This works, with the caveat that
<code class="sourceCode cpp">expr</code> is hashable.</p>
<h3 data-number="5.1.1" id="bitsum-enum-to-string"><span class="header-section-number">5.1.1</span> Bitsum enum-to-string<a href="#bitsum-enum-to-string" class="self-link"></a></h3>
<p>Here is the implementation which handle the sum of flags case. A
generic enum-to-string function should pick this one if all the
enumeration members are power of twos.</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_enum_bitsum_to_string<span class="op">(</span>function_builder<span class="op">&amp;</span> b, decl Enum, expr val, expr res, expr tail<span class="op">)</span> </span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> e <span class="op">:</span> children<span class="op">(</span>Enum<span class="op">))</span></span>
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>val, res, tail, e<span class="op">]</span> </span>
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb41-7"><a href="#cb41-7" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(%</span>val <span class="op">&amp;</span> <span class="op">%</span>e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-8"><a href="#cb41-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(%</span>tail<span class="op">)</span></span>
<span id="cb41-9"><a href="#cb41-9" aria-hidden="true" tabindex="-1"></a>          <span class="op">%</span>res <span class="op">+=</span> <span class="st">&quot; | &quot;</span>;</span>
<span id="cb41-10"><a href="#cb41-10" aria-hidden="true" tabindex="-1"></a>        <span class="op">%</span>res <span class="op">+=</span> <span class="op">%</span>make_literal_expr<span class="op">(</span>identifier_of<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb41-11"><a href="#cb41-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">%</span>tail <span class="op">=</span> <span class="kw">true</span>;</span>
<span id="cb41-12"><a href="#cb41-12" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb41-13"><a href="#cb41-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb41-14"><a href="#cb41-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb41-15"><a href="#cb41-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb41-16"><a href="#cb41-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb41-17"><a href="#cb41-17" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb41-18"><a href="#cb41-18" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>string enum_bitsum_to_string<span class="op">(</span>T val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-19"><a href="#cb41-19" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string res;</span>
<span id="cb41-20"><a href="#cb41-20" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> tail <span class="op">=</span> <span class="kw">false</span>; </span>
<span id="cb41-21"><a href="#cb41-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">%</span>gen_enum_bitsum_to_string<span class="op">(^</span>T, <span class="op">^(</span>val<span class="op">)</span>, <span class="op">^(</span>res<span class="op">)</span>, <span class="op">^(</span>tail<span class="op">))</span>;</span>
<span id="cb41-22"><a href="#cb41-22" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> res;</span>
<span id="cb41-23"><a href="#cb41-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A similar function implemented with P2996, assuming <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>,
would be essentially the same :</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>string enum_bitsum_to_string<span class="op">(</span>T val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string res;</span>
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> tail <span class="op">=</span> <span class="kw">false</span>; </span>
<span id="cb42-5"><a href="#cb42-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> enumerators<span class="op">(^</span>T<span class="op">))</span></span>
<span id="cb42-6"><a href="#cb42-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb42-7"><a href="#cb42-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span> <span class="op">[:</span>e<span class="op">:]</span> <span class="op">&amp;</span> val <span class="op">)</span></span>
<span id="cb42-8"><a href="#cb42-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb42-9"><a href="#cb42-9" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>tail<span class="op">)</span></span>
<span id="cb42-10"><a href="#cb42-10" aria-hidden="true" tabindex="-1"></a>        res <span class="op">+=</span> <span class="st">&quot; | &quot;</span>;</span>
<span id="cb42-11"><a href="#cb42-11" aria-hidden="true" tabindex="-1"></a>      res <span class="op">+=</span> name_of<span class="op">(</span>e<span class="op">)</span>;</span>
<span id="cb42-12"><a href="#cb42-12" aria-hidden="true" tabindex="-1"></a>      tail <span class="op">=</span> <span class="kw">true</span>;</span>
<span id="cb42-13"><a href="#cb42-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb42-14"><a href="#cb42-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb42-15"><a href="#cb42-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> res;</span>
<span id="cb42-16"><a href="#cb42-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.2" id="parsing-command-line-options"><span class="header-section-number">5.2</span> Parsing command-line options<a href="#parsing-command-line-options" class="self-link"></a></h2>
<p>Here we show how to implement a command-line arguments parser. It’s
essentially the same code as P2996, except that <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>
is replaced by repeated injection within an injection statement. Here
again, we have to pass down the reflection of the local values we use in
our injection statement, which is not needed with <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>.</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr to_string_lit_expr<span class="op">(</span>T val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>meta<span class="op">::</span>stringstream ss;</span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a>  ss <span class="op">&lt;&lt;</span> val;</span>
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> make_literal_expr<span class="op">(</span>ss<span class="op">)</span>;</span>
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_parse_args<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr opts, expr args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-9"><a href="#cb43-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> Opts <span class="op">=</span> decl_of<span class="op">(</span>type_of<span class="op">(</span>opts<span class="op">))</span>;</span>
<span id="cb43-10"><a href="#cb43-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> fields<span class="op">(</span>Opts<span class="op">))</span></span>
<span id="cb43-11"><a href="#cb43-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb43-12"><a href="#cb43-12" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>opts, args, f<span class="op">]</span> </span>
<span id="cb43-13"><a href="#cb43-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb43-14"><a href="#cb43-14" aria-hidden="true" tabindex="-1"></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="cb43-15"><a href="#cb43-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">[](</span>std<span class="op">::</span>string_view arg<span class="op">){</span></span>
<span id="cb43-16"><a href="#cb43-16" aria-hidden="true" tabindex="-1"></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> <span class="op">%</span>to_string_lit_expr<span class="op">(</span>identifier_of<span class="op">(</span>f<span class="op">))</span>;</span>
<span id="cb43-17"><a href="#cb43-17" aria-hidden="true" tabindex="-1"></a>      <span class="op">})</span>;</span>
<span id="cb43-18"><a href="#cb43-18" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb43-19"><a href="#cb43-19" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>it <span class="op">==</span> <span class="op">(%</span>args<span class="op">).</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb43-20"><a href="#cb43-20" aria-hidden="true" tabindex="-1"></a>        <span class="co">// no option provided, use default</span></span>
<span id="cb43-21"><a href="#cb43-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">continue</span>;</span>
<span id="cb43-22"><a href="#cb43-22" aria-hidden="true" tabindex="-1"></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> <span class="op">(%</span>args<span class="op">).</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb43-23"><a href="#cb43-23" aria-hidden="true" tabindex="-1"></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="cb43-24"><a href="#cb43-24" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb43-25"><a href="#cb43-25" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb43-26"><a href="#cb43-26" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb43-27"><a href="#cb43-27" aria-hidden="true" tabindex="-1"></a>      <span class="kw">using</span> T <span class="op">=</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>type_of<span class="op">(</span>f<span class="op">))</span>;</span>
<span id="cb43-28"><a href="#cb43-28" aria-hidden="true" tabindex="-1"></a>      </span>
<span id="cb43-29"><a href="#cb43-29" aria-hidden="true" tabindex="-1"></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="cb43-30"><a href="#cb43-30" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>iss <span class="op">&gt;&gt;</span> <span class="op">(%</span>opts<span class="op">).%(</span>f<span class="op">)</span>; <span class="op">!</span>iss<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-31"><a href="#cb43-31" aria-hidden="true" tabindex="-1"></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, <span class="op">%</span>to_string_lit_expr<span class="op">(^</span>T<span class="op">))</span>;</span>
<span id="cb43-32"><a href="#cb43-32" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>exit<span class="op">(</span>EXIT_FAILURE<span class="op">)</span>;</span>
<span id="cb43-33"><a href="#cb43-33" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb43-34"><a href="#cb43-34" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb43-35"><a href="#cb43-35" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb43-36"><a href="#cb43-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb43-37"><a href="#cb43-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb43-38"><a href="#cb43-38" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Opts<span class="op">&gt;</span></span>
<span id="cb43-39"><a href="#cb43-39" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> parse_args<span class="op">(</span>std<span class="op">::</span>span<span class="op">&lt;</span>std<span class="op">::</span>string_view<span class="op">&gt;</span> args<span class="op">)</span> </span>
<span id="cb43-40"><a href="#cb43-40" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb43-41"><a href="#cb43-41" aria-hidden="true" tabindex="-1"></a>  parse_result<span class="op">&lt;</span>Opts<span class="op">&gt;</span> opts;</span>
<span id="cb43-42"><a href="#cb43-42" aria-hidden="true" tabindex="-1"></a>  <span class="op">%</span>gen_parse_args<span class="op">(^(</span>opts<span class="op">)</span>, <span class="op">^(</span>args<span class="op">))</span>;</span>
<span id="cb43-43"><a href="#cb43-43" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> opts;</span>
<span id="cb43-44"><a href="#cb43-44" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.3" id="tuple"><span class="header-section-number">5.3</span> Tuple<a href="#tuple" class="self-link"></a></h2>
<p>Since our model allows to generate code within declarations, we can
inject all the fields of tuple directly, and keep it a simple aggregate.
The function <code class="sourceCode cpp">expand_as_fields</code>
creates the members
<code class="sourceCode cpp">m0</code>…<code class="sourceCode cpp">mN</code>.
<code class="sourceCode cpp">apply</code> and
<code class="sourceCode cpp">tuple_cat</code> are both implemented by
the function <code class="sourceCode cpp">expand_fields</code>, which
performs an expansion for each element of an expression list.</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> expand_as_fields<span class="op">(</span>class_builder<span class="op">&amp;</span> b, type_list tl<span class="op">)</span></span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> t <span class="op">:</span> tl<span class="op">)</span></span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>t, p <span class="op">=</span> k<span class="op">++]</span> <span class="kw">struct</span> <span class="op">{</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>t<span class="op">)</span> <span class="op">%</span>name<span class="op">(</span>cat<span class="op">(</span><span class="st">&quot;m&quot;</span>, p<span class="op">))</span>; <span class="op">}</span>;</span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-8"><a href="#cb44-8" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> collect_fields<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>expr_list<span class="op">&amp;</span> el, std<span class="op">::</span>meta<span class="op">::</span>expr e<span class="op">)</span></span>
<span id="cb44-9"><a href="#cb44-9" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-10"><a href="#cb44-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>meta;</span>
<span id="cb44-11"><a href="#cb44-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> cd <span class="op">=</span> decl_of<span class="op">(</span>remove_reference<span class="op">(</span>type_of<span class="op">(</span>e<span class="op">)))</span>;</span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> fd <span class="op">:</span> fields<span class="op">(</span>cd<span class="op">))</span></span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a>    push_back<span class="op">(</span>el, <span class="op">^</span> <span class="op">[</span>e, fd<span class="op">]</span> <span class="op">((%</span>e<span class="op">).%(</span>fd<span class="op">)))</span>; </span>
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>expr_list expand_fields<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>expr_list el<span class="op">)</span></span>
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-18"><a href="#cb44-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>meta;</span>
<span id="cb44-19"><a href="#cb44-19" aria-hidden="true" tabindex="-1"></a>  expr_list res;</span>
<span id="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span>expr e <span class="op">:</span> el<span class="op">)</span></span>
<span id="cb44-21"><a href="#cb44-21" aria-hidden="true" tabindex="-1"></a>    collect_fields<span class="op">(</span>res, e<span class="op">)</span>;</span>
<span id="cb44-22"><a href="#cb44-22" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> res;</span>
<span id="cb44-23"><a href="#cb44-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-24"><a href="#cb44-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-25"><a href="#cb44-25" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>expr get_by_type<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>type T, std<span class="op">::</span>meta<span class="op">::</span>expr E<span class="op">)</span></span>
<span id="cb44-26"><a href="#cb44-26" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-27"><a href="#cb44-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> cd <span class="op">=</span> decl_of<span class="op">(</span>remove_reference<span class="op">(</span>type_of<span class="op">(</span>E<span class="op">)))</span>;</span>
<span id="cb44-28"><a href="#cb44-28" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> fd <span class="op">:</span> fields<span class="op">(</span>cd<span class="op">))</span></span>
<span id="cb44-29"><a href="#cb44-29" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>type_of<span class="op">(</span>fd<span class="op">)</span> <span class="op">==</span> T<span class="op">)</span></span>
<span id="cb44-30"><a href="#cb44-30" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>E, fd<span class="op">]</span> <span class="op">(</span> <span class="op">(%</span>E<span class="op">).%(</span>fd<span class="op">)</span> <span class="op">)</span>;</span>
<span id="cb44-31"><a href="#cb44-31" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>meta<span class="op">::</span>stringstream os;</span>
<span id="cb44-32"><a href="#cb44-32" aria-hidden="true" tabindex="-1"></a>  os <span class="op">&lt;&lt;</span> <span class="st">&quot;type &quot;</span> <span class="op">&lt;&lt;</span> T <span class="op">&lt;&lt;</span> <span class="st">&quot; not contained in &quot;</span> <span class="op">&lt;&lt;</span> cd;</span>
<span id="cb44-33"><a href="#cb44-33" aria-hidden="true" tabindex="-1"></a>  error<span class="op">(</span>os<span class="op">)</span>;</span>
<span id="cb44-34"><a href="#cb44-34" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb44-35"><a href="#cb44-35" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-36"><a href="#cb44-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-37"><a href="#cb44-37" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb44-38"><a href="#cb44-38" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tuple</span>
<span id="cb44-39"><a href="#cb44-39" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-40"><a href="#cb44-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">&lt;=&gt;(</span><span class="kw">const</span> tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&amp;</span> ts<span class="op">)</span> <span class="kw">const</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb44-41"><a href="#cb44-41" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb44-42"><a href="#cb44-42" aria-hidden="true" tabindex="-1"></a>  <span class="op">%</span>expand_as_fields<span class="op">(</span>type_list<span class="op">{^</span>Ts<span class="op">...})</span>;</span>
<span id="cb44-43"><a href="#cb44-43" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb44-44"><a href="#cb44-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-45"><a href="#cb44-45" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> Index, <span class="kw">class</span> Tpl<span class="op">&gt;</span></span>
<span id="cb44-46"><a href="#cb44-46" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span> std<span class="op">::</span>meta<span class="op">::</span>is_instance_of<span class="op">(^</span>Tpl, <span class="op">^</span>tuple<span class="op">)</span> <span class="op">)</span></span>
<span id="cb44-47"><a href="#cb44-47" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> get<span class="op">(</span>Tpl<span class="op">&amp;&amp;</span> tpl<span class="op">)</span></span>
<span id="cb44-48"><a href="#cb44-48" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-49"><a href="#cb44-49" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> tpl<span class="op">.%(</span>fields<span class="op">(^</span>Tpl<span class="op">)[</span>Index<span class="op">])</span>; </span>
<span id="cb44-50"><a href="#cb44-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-51"><a href="#cb44-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-52"><a href="#cb44-52" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> Tpl<span class="op">&gt;</span></span>
<span id="cb44-53"><a href="#cb44-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span> std<span class="op">::</span>meta<span class="op">::</span>is_instance_of<span class="op">(^</span>Tpl, <span class="op">^</span>tuple<span class="op">)</span> <span class="op">)</span></span>
<span id="cb44-54"><a href="#cb44-54" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> get<span class="op">(</span>Tpl<span class="op">&amp;&amp;</span> tpl<span class="op">)</span></span>
<span id="cb44-55"><a href="#cb44-55" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-56"><a href="#cb44-56" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">%</span>get_by_type<span class="op">(^</span>Tpl, <span class="op">^(</span>tpl<span class="op">))</span>;</span>
<span id="cb44-57"><a href="#cb44-57" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-58"><a href="#cb44-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-59"><a href="#cb44-59" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> impl</span>
<span id="cb44-60"><a href="#cb44-60" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-61"><a href="#cb44-61" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> type tuple_cat_result_type<span class="op">(</span>type_list tl<span class="op">)</span> </span>
<span id="cb44-62"><a href="#cb44-62" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb44-63"><a href="#cb44-63" aria-hidden="true" tabindex="-1"></a>    template_argument_list args;</span>
<span id="cb44-64"><a href="#cb44-64" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> t <span class="op">:</span> tl<span class="op">)</span></span>
<span id="cb44-65"><a href="#cb44-65" aria-hidden="true" tabindex="-1"></a>      <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> a <span class="op">:</span> template_arguments_of<span class="op">(</span>t<span class="op">))</span></span>
<span id="cb44-66"><a href="#cb44-66" aria-hidden="true" tabindex="-1"></a>        push_back<span class="op">(</span>args, a<span class="op">)</span>; </span>
<span id="cb44-67"><a href="#cb44-67" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> substitute<span class="op">(^</span>tuple, args<span class="op">)</span>;</span>
<span id="cb44-68"><a href="#cb44-68" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-69"><a href="#cb44-69" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-70"><a href="#cb44-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-71"><a href="#cb44-71" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb44-72"><a href="#cb44-72" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span> std<span class="op">::</span>meta<span class="op">::</span>is_instance_of<span class="op">(^</span>Ts, <span class="op">^</span>tuple<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...</span> <span class="op">)</span> </span>
<span id="cb44-73"><a href="#cb44-73" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> tuple_cat<span class="op">(</span>Ts<span class="op">&amp;&amp;...</span> ts<span class="op">)</span></span>
<span id="cb44-74"><a href="#cb44-74" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-75"><a href="#cb44-75" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> ResultType <span class="op">=</span> <span class="op">%</span>impl<span class="op">::</span>tuple_cat_result_type<span class="op">(</span> <span class="op">{</span>remove_reference<span class="op">(^</span>Ts<span class="op">)...}</span> <span class="op">)</span>;</span>
<span id="cb44-76"><a href="#cb44-76" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ResultType<span class="op">{</span> <span class="op">%...</span>expand_fields<span class="op">(^(</span>ts<span class="op">...))...</span> <span class="op">}</span>;</span>
<span id="cb44-77"><a href="#cb44-77" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb44-78"><a href="#cb44-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-79"><a href="#cb44-79" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Fn, <span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb44-80"><a href="#cb44-80" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span> std<span class="op">::</span>meta<span class="op">::</span>is_instance_of<span class="op">(^</span>Ts, <span class="op">^</span>tuple<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...</span> <span class="op">)</span></span>
<span id="cb44-81"><a href="#cb44-81" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> apply<span class="op">(</span>Fn fn, Ts<span class="op">&amp;&amp;...</span> ts<span class="op">)</span></span>
<span id="cb44-82"><a href="#cb44-82" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb44-83"><a href="#cb44-83" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> fn<span class="op">(</span> <span class="op">%...</span>expand_fields<span class="op">(^(</span>ts<span class="op">...))...</span> <span class="op">)</span>;</span>
<span id="cb44-84"><a href="#cb44-84" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.3.1" id="comparison-with-p2296"><span class="header-section-number">5.3.1</span> Comparison with P2296<a href="#comparison-with-p2296" class="self-link"></a></h3>
<p>P2996 cannot inject code within a declaration, therefore their
implementation of tuple cannot be a simple aggregate and must declare a
constructor, which is both an ergonomic and performance loss. Otherwise,
the implementation of <code class="sourceCode cpp">get</code> is the
same.</p>
<p>Here is their implementation of
<code class="sourceCode cpp">tuple_cat</code>, thanks to Tomasz Kaminski
:</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span>pair<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span>, std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;...</span> indices<span class="op">&gt;</span></span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Indexer <span class="op">{</span></span>
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a>   <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> Tuples<span class="op">&gt;</span></span>
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a>   <span class="co">// Can use tuple indexing instead of tuple of tuples</span></span>
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a>   <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>Tuples<span class="op">&amp;&amp;</span> tuples<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a>     <span class="kw">using</span> ResultType <span class="op">=</span> std<span class="op">::</span>tuple<span class="op">&lt;</span></span>
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a>       std<span class="op">::</span>tuple_element_t<span class="op">&lt;</span></span>
<span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a>         indices<span class="op">.</span>second,</span>
<span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>std<span class="op">::</span>tuple_element_t<span class="op">&lt;</span>indices<span class="op">.</span>first, std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Tuples<span class="op">&gt;&gt;&gt;</span></span>
<span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a>       <span class="op">&gt;...</span></span>
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a>     <span class="op">&gt;</span>;</span>
<span id="cb45-12"><a href="#cb45-12" aria-hidden="true" tabindex="-1"></a>     <span class="cf">return</span> ResultType<span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>indices<span class="op">.</span>second<span class="op">&gt;(</span>std<span class="op">::</span>get<span class="op">&lt;</span>indices<span class="op">.</span>first<span class="op">&gt;(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Tuples<span class="op">&gt;(</span>tuples<span class="op">)))...)</span>;</span>
<span id="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a>   <span class="op">}</span></span>
<span id="cb45-14"><a href="#cb45-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb45-15"><a href="#cb45-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-16"><a href="#cb45-16" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb45-17"><a href="#cb45-17" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> subst_by_value<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info tmpl, std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span> args<span class="op">)</span></span>
<span id="cb45-18"><a href="#cb45-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info</span>
<span id="cb45-19"><a href="#cb45-19" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb45-20"><a href="#cb45-20" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>meta<span class="op">::</span>info<span class="op">&gt;</span> a2;</span>
<span id="cb45-21"><a href="#cb45-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span>T x <span class="op">:</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb45-22"><a href="#cb45-22" aria-hidden="true" tabindex="-1"></a>        a2<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>x<span class="op">))</span>;</span>
<span id="cb45-23"><a href="#cb45-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb45-24"><a href="#cb45-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-25"><a href="#cb45-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> substitute<span class="op">(</span>tmpl, a2<span class="op">)</span>;</span>
<span id="cb45-26"><a href="#cb45-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb45-27"><a href="#cb45-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-28"><a href="#cb45-28" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> make_indexer<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;</span> sizes<span class="op">)</span></span>
<span id="cb45-29"><a href="#cb45-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> std<span class="op">::</span>meta<span class="op">::</span>info</span>
<span id="cb45-30"><a href="#cb45-30" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb45-31"><a href="#cb45-31" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>pair<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;&gt;</span> args;</span>
<span id="cb45-32"><a href="#cb45-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-33"><a href="#cb45-33" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span><span class="dt">size_t</span> tidx <span class="op">=</span> <span class="dv">0</span>; tidx <span class="op">&lt;</span> sizes<span class="op">.</span>size<span class="op">()</span>; <span class="op">++</span>tidx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb45-34"><a href="#cb45-34" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span><span class="dt">size_t</span> eidx <span class="op">=</span> <span class="dv">0</span>; eidx <span class="op">&lt;</span> sizes<span class="op">[</span>tidx<span class="op">]</span>; <span class="op">++</span>eidx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb45-35"><a href="#cb45-35" aria-hidden="true" tabindex="-1"></a>            args<span class="op">.</span>push_back<span class="op">({</span>tidx, eidx<span class="op">})</span>;</span>
<span id="cb45-36"><a href="#cb45-36" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb45-37"><a href="#cb45-37" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb45-38"><a href="#cb45-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-39"><a href="#cb45-39" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> subst_by_value<span class="op">(^</span>Indexer, args<span class="op">)</span>;</span>
<span id="cb45-40"><a href="#cb45-40" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb45-41"><a href="#cb45-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-42"><a href="#cb45-42" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Tuples<span class="op">&gt;</span></span>
<span id="cb45-43"><a href="#cb45-43" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> my_tuple_cat<span class="op">(</span>Tuples<span class="op">&amp;&amp;...</span> tuples<span class="op">)</span> <span class="op">{</span></span>
<span id="cb45-44"><a href="#cb45-44" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">typename</span> <span class="op">[:</span> make_indexer<span class="op">({</span>type_tuple_size<span class="op">(</span>type_remove_cvref<span class="op">(^</span>Tuples<span class="op">))...})</span> <span class="op">:]</span> indexer;</span>
<span id="cb45-45"><a href="#cb45-45" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> indexer<span class="op">(</span>std<span class="op">::</span>forward_as_tuple<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Tuples<span class="op">&gt;(</span>tuples<span class="op">)...))</span>;</span>
<span id="cb45-46"><a href="#cb45-46" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It still has to rely on rather elaborate template meta-programming,
but P2296 helps in the construction of a pack of pair of indices.</p>
<h2 data-number="5.4" id="variant"><span class="header-section-number">5.4</span> Variant<a href="#variant" class="self-link"></a></h2>
<p>Here we reuse the
<code class="sourceCode cpp">expand_as_fields</code> function defined
above to generate the variant storage. This code is pretty much the same
as the implementation of P2296, except for the storage and
<code class="sourceCode cpp">visit</code> (which they do not implement –
it could be done with <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>,
though it would result in a chain of
<code class="sourceCode cpp"><span class="cf">if</span></code>).</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">int</span> N<span class="op">&gt;</span></span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> constant <span class="op">{</span></span>
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> value <span class="op">=</span> N;</span>
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb46-5"><a href="#cb46-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-6"><a href="#cb46-6" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_visit<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr data, expr vis<span class="op">)</span> </span>
<span id="cb46-7"><a href="#cb46-7" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb46-8"><a href="#cb46-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> d <span class="op">=</span> decl_of<span class="op">(</span>type_of<span class="op">(</span>data<span class="op">))</span>;</span>
<span id="cb46-9"><a href="#cb46-9" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb46-10"><a href="#cb46-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> fields<span class="op">(</span>d<span class="op">))</span></span>
<span id="cb46-11"><a href="#cb46-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-12"><a href="#cb46-12" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>data, vis, p <span class="op">=</span> k<span class="op">++]</span></span>
<span id="cb46-13"><a href="#cb46-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb46-14"><a href="#cb46-14" aria-hidden="true" tabindex="-1"></a>      <span class="cf">case</span> p <span class="op">:</span> <span class="cf">return</span> <span class="op">(%</span>vis<span class="op">)(</span> <span class="op">(%</span>data<span class="op">).%(</span>f<span class="op">)</span> <span class="op">)</span>;</span>
<span id="cb46-15"><a href="#cb46-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb46-16"><a href="#cb46-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-17"><a href="#cb46-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb46-18"><a href="#cb46-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-19"><a href="#cb46-19" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_visit_with_index<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr data, expr vis<span class="op">)</span> </span>
<span id="cb46-20"><a href="#cb46-20" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb46-21"><a href="#cb46-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> d <span class="op">=</span> decl_of<span class="op">(</span>type_of<span class="op">(</span>data<span class="op">))</span>;</span>
<span id="cb46-22"><a href="#cb46-22" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb46-23"><a href="#cb46-23" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> fields<span class="op">(</span>d<span class="op">))</span></span>
<span id="cb46-24"><a href="#cb46-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-25"><a href="#cb46-25" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>data, vis, p <span class="op">=</span> k<span class="op">++]</span></span>
<span id="cb46-26"><a href="#cb46-26" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb46-27"><a href="#cb46-27" aria-hidden="true" tabindex="-1"></a>      <span class="cf">case</span> p <span class="op">:</span> <span class="cf">return</span> <span class="op">(%</span>vis<span class="op">)(</span> <span class="op">(%</span>data<span class="op">).%(</span>f<span class="op">)</span>, constant<span class="op">&lt;</span>p<span class="op">&gt;{}</span> <span class="op">)</span>;</span>
<span id="cb46-28"><a href="#cb46-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb46-29"><a href="#cb46-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-30"><a href="#cb46-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb46-31"><a href="#cb46-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb46-32"><a href="#cb46-32" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb46-33"><a href="#cb46-33" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> variant <span class="op">:</span> variant_base</span>
<span id="cb46-34"><a href="#cb46-34" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb46-35"><a href="#cb46-35" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> trivial_dtor <span class="op">=</span> <span class="op">(</span>is_trivially_destructible<span class="op">(^</span>Ts<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span>;</span>
<span id="cb46-36"><a href="#cb46-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> ctor_selector <span class="op">=</span> impl<span class="op">::</span>overload_selector<span class="op">&lt;</span>Ts<span class="op">...&gt;</span>;</span>
<span id="cb46-37"><a href="#cb46-37" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-38"><a href="#cb46-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">consteval</span> type alternative<span class="op">(</span><span class="dt">unsigned</span> idx<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> type_list<span class="op">{^</span>Ts<span class="op">...}[</span>idx<span class="op">]</span>; <span class="op">}</span></span>
<span id="cb46-39"><a href="#cb46-39" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">consteval</span> <span class="dt">unsigned</span> index_of<span class="op">(</span>type T<span class="op">)</span>      <span class="op">{</span> <span class="cf">return</span> impl<span class="op">::</span>find_first_pos<span class="op">(</span>type_list<span class="op">{^</span>Ts<span class="op">...}</span>, T<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb46-40"><a href="#cb46-40" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-41"><a href="#cb46-41" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb46-42"><a href="#cb46-42" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> variant<span class="op">(</span>Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span></span>
<span id="cb46-43"><a href="#cb46-43" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">((</span><span class="kw">sizeof</span><span class="op">...(</span>Args<span class="op">)</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="kw">requires</span> <span class="op">{</span> impl<span class="op">::</span>ctor_selector<span class="op">{}({(</span>Args<span class="op">&amp;&amp;)</span>args<span class="op">...})</span>; <span class="op">})</span> </span>
<span id="cb46-44"><a href="#cb46-44" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> data<span class="op">{}</span></span>
<span id="cb46-45"><a href="#cb46-45" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-46"><a href="#cb46-46" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> emplace_idx <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span> impl<span class="op">::</span>ctor_selector<span class="op">{}({(</span>Args<span class="op">&amp;&amp;)</span>args<span class="op">...})</span> <span class="op">)::</span>value;</span>
<span id="cb46-47"><a href="#cb46-47" aria-hidden="true" tabindex="-1"></a>    data<span class="op">.</span><span class="kw">template</span> emplace<span class="op">&lt;</span>emplace_idx<span class="op">&gt;(</span> <span class="op">(</span>Args<span class="op">&amp;&amp;)</span> args<span class="op">...</span> <span class="op">)</span>;</span>
<span id="cb46-48"><a href="#cb46-48" aria-hidden="true" tabindex="-1"></a>    index_m <span class="op">=</span> emplace_idx;</span>
<span id="cb46-49"><a href="#cb46-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-50"><a href="#cb46-50" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-51"><a href="#cb46-51" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> variant<span class="op">(</span><span class="kw">const</span> variant<span class="op">&amp;</span> v<span class="op">)</span></span>
<span id="cb46-52"><a href="#cb46-52" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> data<span class="op">{}</span></span>
<span id="cb46-53"><a href="#cb46-53" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-54"><a href="#cb46-54" aria-hidden="true" tabindex="-1"></a>    emplace_from<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb46-55"><a href="#cb46-55" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-56"><a href="#cb46-56" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-57"><a href="#cb46-57" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> variant<span class="op">(</span>variant<span class="op">&amp;&amp;</span> v<span class="op">)</span></span>
<span id="cb46-58"><a href="#cb46-58" aria-hidden="true" tabindex="-1"></a>    <span class="kw">noexcept</span> <span class="op">((</span>is_nothrow_move_constructible<span class="op">(^</span>Ts<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...))</span></span>
<span id="cb46-59"><a href="#cb46-59" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span>is_move_constructible<span class="op">(^</span>Ts<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></span>
<span id="cb46-60"><a href="#cb46-60" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> data<span class="op">{}</span></span>
<span id="cb46-61"><a href="#cb46-61" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-62"><a href="#cb46-62" aria-hidden="true" tabindex="-1"></a>    emplace_from<span class="op">((</span>variant<span class="op">&amp;&amp;)</span> v<span class="op">)</span>;</span>
<span id="cb46-63"><a href="#cb46-63" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-64"><a href="#cb46-64" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-65"><a href="#cb46-65" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> N, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb46-66"><a href="#cb46-66" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> emplace<span class="op">(</span>Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-67"><a href="#cb46-67" aria-hidden="true" tabindex="-1"></a>    destroy<span class="op">()</span>;</span>
<span id="cb46-68"><a href="#cb46-68" aria-hidden="true" tabindex="-1"></a>    data<span class="op">.</span><span class="kw">template</span> emplace<span class="op">&lt;</span>N<span class="op">&gt;(</span> <span class="op">(</span>Args<span class="op">&amp;&amp;)</span> args<span class="op">...</span> <span class="op">)</span>;</span>
<span id="cb46-69"><a href="#cb46-69" aria-hidden="true" tabindex="-1"></a>    index_m <span class="op">=</span> N;</span>
<span id="cb46-70"><a href="#cb46-70" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-71"><a href="#cb46-71" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-72"><a href="#cb46-72" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> variant<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> variant<span class="op">&amp;</span> o<span class="op">)</span> </span>
<span id="cb46-73"><a href="#cb46-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span>is_assignable<span class="op">(^</span>Ts<span class="op">)</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></span>
<span id="cb46-74"><a href="#cb46-74" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-75"><a href="#cb46-75" aria-hidden="true" tabindex="-1"></a>    destroy<span class="op">()</span>;</span>
<span id="cb46-76"><a href="#cb46-76" aria-hidden="true" tabindex="-1"></a>    emplace_from<span class="op">(</span>o<span class="op">)</span>;</span>
<span id="cb46-77"><a href="#cb46-77" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-78"><a href="#cb46-78" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-79"><a href="#cb46-79" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> index<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb46-80"><a href="#cb46-80" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> index_m;</span>
<span id="cb46-81"><a href="#cb46-81" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-82"><a href="#cb46-82" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-83"><a href="#cb46-83" aria-hidden="true" tabindex="-1"></a>  <span class="kw">union</span> Data </span>
<span id="cb46-84"><a href="#cb46-84" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-85"><a href="#cb46-85" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> Data<span class="op">()</span> </span>
<span id="cb46-86"><a href="#cb46-86" aria-hidden="true" tabindex="-1"></a>    <span class="op">:</span> xxx<span class="op">{}</span></span>
<span id="cb46-87"><a href="#cb46-87" aria-hidden="true" tabindex="-1"></a>    <span class="op">{}</span></span>
<span id="cb46-88"><a href="#cb46-88" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb46-89"><a href="#cb46-89" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> N, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb46-90"><a href="#cb46-90" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> Data<span class="op">(</span>emplace_at_index<span class="op">&lt;</span>N<span class="op">&gt;</span>, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> </span>
<span id="cb46-91"><a href="#cb46-91" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb46-92"><a href="#cb46-92" aria-hidden="true" tabindex="-1"></a>      <span class="kw">this</span><span class="op">-&gt;</span>emplace<span class="op">&lt;</span>N<span class="op">&gt;((</span>Args<span class="op">&amp;&amp;)</span>args<span class="op">...)</span>;</span>
<span id="cb46-93"><a href="#cb46-93" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb46-94"><a href="#cb46-94" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb46-95"><a href="#cb46-95" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> N, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb46-96"><a href="#cb46-96" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">void</span> emplace<span class="op">(</span>Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-97"><a href="#cb46-97" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>construct_at<span class="op">(</span> <span class="op">&amp;</span><span class="kw">this</span><span class="op">-&gt;%(</span>cat<span class="op">(</span><span class="st">&quot;m&quot;</span>, N<span class="op">))</span>, <span class="op">(</span>Args<span class="op">&amp;&amp;)</span>args<span class="op">...</span> <span class="op">)</span>;</span>
<span id="cb46-98"><a href="#cb46-98" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb46-99"><a href="#cb46-99" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb46-100"><a href="#cb46-100" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="op">~</span>Data<span class="op">()</span> </span>
<span id="cb46-101"><a href="#cb46-101" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <span class="op">(</span><span class="kw">not</span> trivial_dtor<span class="op">)</span></span>
<span id="cb46-102"><a href="#cb46-102" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb46-103"><a href="#cb46-103" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb46-104"><a href="#cb46-104" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb46-105"><a href="#cb46-105" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="op">~</span>Data<span class="op">()</span></span>
<span id="cb46-106"><a href="#cb46-106" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <span class="op">(</span>trivial_dtor<span class="op">)</span></span>
<span id="cb46-107"><a href="#cb46-107" aria-hidden="true" tabindex="-1"></a>    <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb46-108"><a href="#cb46-108" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb46-109"><a href="#cb46-109" aria-hidden="true" tabindex="-1"></a>    impl<span class="op">::</span>empty_t xxx;</span>
<span id="cb46-110"><a href="#cb46-110" aria-hidden="true" tabindex="-1"></a>    <span class="op">%</span>expand_as_fields<span class="op">(</span>type_list<span class="op">{^</span>Ts<span class="op">...})</span>;</span>
<span id="cb46-111"><a href="#cb46-111" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb46-112"><a href="#cb46-112" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-113"><a href="#cb46-113" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="op">~</span>variant<span class="op">()</span> </span>
<span id="cb46-114"><a href="#cb46-114" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span><span class="kw">not</span> trivial_dtor<span class="op">)</span></span>
<span id="cb46-115"><a href="#cb46-115" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-116"><a href="#cb46-116" aria-hidden="true" tabindex="-1"></a>    visit<span class="op">(</span> impl<span class="op">::</span>destruct_element<span class="op">{}</span>, <span class="op">*</span><span class="kw">this</span> <span class="op">)</span>;</span>
<span id="cb46-117"><a href="#cb46-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-118"><a href="#cb46-118" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-119"><a href="#cb46-119" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="op">~</span>variant<span class="op">()</span> </span>
<span id="cb46-120"><a href="#cb46-120" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span>trivial_dtor<span class="op">)</span></span>
<span id="cb46-121"><a href="#cb46-121" aria-hidden="true" tabindex="-1"></a>  <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb46-122"><a href="#cb46-122" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-123"><a href="#cb46-123" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> Index<span class="op">&gt;</span></span>
<span id="cb46-124"><a href="#cb46-124" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span><span class="op">&amp;</span> get<span class="op">(</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self<span class="op">)</span> <span class="op">{</span> </span>
<span id="cb46-125"><a href="#cb46-125" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> self<span class="op">.</span>data<span class="op">.%(</span>fields<span class="op">(^</span>Data<span class="op">)[</span>Index <span class="op">+</span> <span class="dv">1</span><span class="op">])</span>; </span>
<span id="cb46-126"><a href="#cb46-126" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-127"><a href="#cb46-127" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-128"><a href="#cb46-128" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb46-129"><a href="#cb46-129" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> T<span class="op">&amp;</span> get<span class="op">(</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> self<span class="op">.</span>get<span class="op">&lt;</span>index_of<span class="op">(^</span>T<span class="op">)&gt;()</span>; <span class="op">}</span></span>
<span id="cb46-130"><a href="#cb46-130" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-131"><a href="#cb46-131" aria-hidden="true" tabindex="-1"></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="cb46-132"><a href="#cb46-132" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> visit<span class="op">(</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self, F<span class="op">&amp;&amp;</span> fn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-133"><a href="#cb46-133" aria-hidden="true" tabindex="-1"></a>    <span class="cf">switch</span><span class="op">(</span>index_m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-134"><a href="#cb46-134" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span>gen_visit<span class="op">(^(</span>self<span class="op">.</span>data<span class="op">)</span>, <span class="op">^(</span>fn<span class="op">))</span>;</span>
<span id="cb46-135"><a href="#cb46-135" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb46-136"><a href="#cb46-136" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-137"><a href="#cb46-137" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-138"><a href="#cb46-138" aria-hidden="true" tabindex="-1"></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="cb46-139"><a href="#cb46-139" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> visit_with_index<span class="op">(</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self, F<span class="op">&amp;&amp;</span> fn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-140"><a href="#cb46-140" aria-hidden="true" tabindex="-1"></a>    <span class="cf">switch</span><span class="op">(</span>index_m<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-141"><a href="#cb46-141" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span>gen_visit_with_index<span class="op">(^(</span>self<span class="op">.</span>data<span class="op">)</span>, <span class="op">^(</span>fn<span class="op">))</span>;</span>
<span id="cb46-142"><a href="#cb46-142" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb46-143"><a href="#cb46-143" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-144"><a href="#cb46-144" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-145"><a href="#cb46-145" aria-hidden="true" tabindex="-1"></a>  Data data;</span>
<span id="cb46-146"><a href="#cb46-146" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-147"><a href="#cb46-147" aria-hidden="true" tabindex="-1"></a>  <span class="kw">private</span> <span class="op">:</span> </span>
<span id="cb46-148"><a href="#cb46-148" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-149"><a href="#cb46-149" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="dt">unsigned</span> Idx, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb46-150"><a href="#cb46-150" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> emplace_no_reset<span class="op">(</span>Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-151"><a href="#cb46-151" aria-hidden="true" tabindex="-1"></a>    data<span class="op">.</span><span class="kw">template</span> emplace<span class="op">&lt;</span>Idx<span class="op">&gt;(</span> <span class="op">(</span>Args<span class="op">&amp;&amp;)</span>args<span class="op">...</span> <span class="op">)</span>;</span>
<span id="cb46-152"><a href="#cb46-152" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-153"><a href="#cb46-153" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-154"><a href="#cb46-154" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> V<span class="op">&gt;</span></span>
<span id="cb46-155"><a href="#cb46-155" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> emplace_from<span class="op">(</span>V<span class="op">&amp;&amp;</span> o<span class="op">)</span> </span>
<span id="cb46-156"><a href="#cb46-156" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb46-157"><a href="#cb46-157" aria-hidden="true" tabindex="-1"></a>    <span class="kw">this</span><span class="op">-&gt;</span>visit_with_index<span class="op">(</span> <span class="op">[]</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> elem, <span class="kw">auto</span> idx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb46-158"><a href="#cb46-158" aria-hidden="true" tabindex="-1"></a>      index_m <span class="op">=</span> idx<span class="op">.</span>value;</span>
<span id="cb46-159"><a href="#cb46-159" aria-hidden="true" tabindex="-1"></a>      <span class="kw">this</span><span class="op">-&gt;</span>emplace_no_reset<span class="op">&lt;</span>idx<span class="op">.</span>value<span class="op">&gt;(</span> elem <span class="op">)</span>;</span>
<span id="cb46-160"><a href="#cb46-160" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, <span class="op">(</span>V<span class="op">&amp;&amp;)</span> o<span class="op">)</span>;</span>
<span id="cb46-161"><a href="#cb46-161" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-162"><a href="#cb46-162" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-163"><a href="#cb46-163" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">void</span> destroy<span class="op">()</span> <span class="op">{</span></span>
<span id="cb46-164"><a href="#cb46-164" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span> <span class="kw">not</span> trivial_dtor <span class="op">)</span></span>
<span id="cb46-165"><a href="#cb46-165" aria-hidden="true" tabindex="-1"></a>      visit<span class="op">(</span> impl<span class="op">::</span>destruct_element<span class="op">{}</span>, <span class="op">*</span><span class="kw">this</span> <span class="op">)</span>;</span>
<span id="cb46-166"><a href="#cb46-166" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb46-167"><a href="#cb46-167" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb46-168"><a href="#cb46-168" aria-hidden="true" tabindex="-1"></a>  <span class="dt">unsigned</span> <span class="dt">char</span> index_m;</span>
<span id="cb46-169"><a href="#cb46-169" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="5.5" id="universal-formatter"><span class="header-section-number">5.5</span> Universal formatter<a href="#universal-formatter" class="self-link"></a></h2>
<p>This is our equivalent implementation of the universal formatter
proposed in P2996. Here again, because we do not have <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>,
we must pass down the reflection of our local values to the injection
function. Otherwise, the code is similar.</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr to_string_lit<span class="op">(</span>type T<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>meta<span class="op">::</span>stringstream os;</span>
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a>  os <span class="op">&lt;&lt;</span> T;</span>
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> make_literal_expr<span class="op">(</span>os<span class="op">)</span>;</span>
<span id="cb47-5"><a href="#cb47-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb47-6"><a href="#cb47-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-7"><a href="#cb47-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> universal_formatter <span class="op">{</span></span>
<span id="cb47-8"><a href="#cb47-8" aria-hidden="true" tabindex="-1"></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="cb47-9"><a href="#cb47-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-10"><a href="#cb47-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb47-11"><a href="#cb47-11" aria-hidden="true" tabindex="-1"></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="cb47-12"><a href="#cb47-12" aria-hidden="true" tabindex="-1"></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>, to_string_lit<span class="op">(^</span>T<span class="op">))</span>;</span>
<span id="cb47-13"><a href="#cb47-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-14"><a href="#cb47-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">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="cb47-15"><a href="#cb47-15" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb47-16"><a href="#cb47-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb47-17"><a href="#cb47-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb47-18"><a href="#cb47-18" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb47-19"><a href="#cb47-19" aria-hidden="true" tabindex="-1"></a>      first <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb47-20"><a href="#cb47-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb47-21"><a href="#cb47-21" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb47-22"><a href="#cb47-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">%</span> <span class="op">[]</span> <span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr out, expr val, expr delim<span class="op">)</span> </span>
<span id="cb47-23"><a href="#cb47-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb47-24"><a href="#cb47-24" aria-hidden="true" tabindex="-1"></a>      <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> base <span class="op">:</span> bases_of<span class="op">(^</span>T<span class="op">))</span></span>
<span id="cb47-25"><a href="#cb47-25" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span></span>
<span id="cb47-26"><a href="#cb47-26" aria-hidden="true" tabindex="-1"></a>        b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>out, val, delim, base<span class="op">]</span> <span class="op">{</span></span>
<span id="cb47-27"><a href="#cb47-27" aria-hidden="true" tabindex="-1"></a>          <span class="op">%</span>delim;</span>
<span id="cb47-28"><a href="#cb47-28" aria-hidden="true" tabindex="-1"></a>          <span class="op">%</span>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> <span class="op">%</span>base <span class="op">&gt;(%</span>val<span class="op">))</span>;</span>
<span id="cb47-29"><a href="#cb47-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb47-30"><a href="#cb47-30" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb47-31"><a href="#cb47-31" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="op">(^(</span>out<span class="op">)</span>, <span class="op">^(</span>t<span class="op">)</span>, <span class="op">^(</span>delim<span class="op">()))</span>;</span>
<span id="cb47-32"><a href="#cb47-32" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb47-33"><a href="#cb47-33" aria-hidden="true" tabindex="-1"></a>    <span class="op">%</span> <span class="op">[]</span> <span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr out, expr val, expr delim<span class="op">)</span> </span>
<span id="cb47-34"><a href="#cb47-34" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb47-35"><a href="#cb47-35" aria-hidden="true" tabindex="-1"></a>      <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> fields<span class="op">(^</span>T<span class="op">))</span></span>
<span id="cb47-36"><a href="#cb47-36" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span></span>
<span id="cb47-37"><a href="#cb47-37" aria-hidden="true" tabindex="-1"></a>        b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>out, val, delim, f<span class="op">]</span> <span class="op">{</span></span>
<span id="cb47-38"><a href="#cb47-38" aria-hidden="true" tabindex="-1"></a>          <span class="op">%</span>delim;</span>
<span id="cb47-39"><a href="#cb47-39" aria-hidden="true" tabindex="-1"></a>          <span class="op">%</span>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="op">(%</span>val<span class="op">).%(</span>f<span class="op">))</span>;</span>
<span id="cb47-40"><a href="#cb47-40" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb47-41"><a href="#cb47-41" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb47-42"><a href="#cb47-42" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="op">(^(</span>out<span class="op">)</span>, <span class="op">^(</span>t<span class="op">)</span>, <span class="op">^(</span>delim<span class="op">()))</span>;</span>
<span id="cb47-43"><a href="#cb47-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb47-44"><a href="#cb47-44" aria-hidden="true" tabindex="-1"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;}&#39;</span>;</span>
<span id="cb47-45"><a href="#cb47-45" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> out;</span>
<span id="cb47-46"><a href="#cb47-46" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb47-47"><a href="#cb47-47" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="5.6" id="operators-generation"><span class="header-section-number">5.6</span> Operators generation<a href="#operators-generation" class="self-link"></a></h2>
<p>Probably our most compelling use-case so far is operators generation.
The way we achieve this is by delegating the implementation to a member
function <code class="sourceCode cpp">apply_op</code> taking an
<code class="sourceCode cpp">operator_kind</code> as template argument.
Within the body of this member function, the user can construct an
operator expression generically from the template argument (using
<code class="sourceCode cpp">make_operator_expr</code>, or operator
injection).</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> declare_op<span class="op">(</span>class_builder<span class="op">&amp;</span> b, type operand_type, operator_kind op<span class="op">)</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> this_ty <span class="op">=</span> type_of<span class="op">(</span>b<span class="op">)</span>; </span>
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(!</span>std<span class="op">::</span>meta<span class="op">::</span>is_compound_assign<span class="op">(</span>op<span class="op">))</span></span>
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a>    this_ty <span class="op">=</span> add_const<span class="op">(</span>this_ty<span class="op">)</span>;</span>
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a>  this_ty <span class="op">=</span> add_lvalue_reference<span class="op">(</span>this_ty<span class="op">)</span>;</span>
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>this_ty, operand_type, op<span class="op">]</span> <span class="kw">struct</span> </span>
<span id="cb48-10"><a href="#cb48-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb48-11"><a href="#cb48-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">%</span>name<span class="op">(</span>op<span class="op">)</span> <span class="op">(</span><span class="kw">this</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>this_ty<span class="op">)</span> self, <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>operand_type<span class="op">)</span> rhs<span class="op">)</span> <span class="op">{</span></span>
<span id="cb48-12"><a href="#cb48-12" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> self<span class="op">.</span><span class="kw">template</span> apply_op<span class="op">&lt;</span>op<span class="op">&gt;(</span>rhs<span class="op">)</span>;</span>
<span id="cb48-13"><a href="#cb48-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb48-14"><a href="#cb48-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb48-15"><a href="#cb48-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb48-16"><a href="#cb48-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-17"><a href="#cb48-17" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> declare_operators<span class="op">(</span>class_builder<span class="op">&amp;</span> b, type operand_type, std<span class="op">::</span>span<span class="op">&lt;</span>operator_kind<span class="op">&gt;</span> ops<span class="op">)</span></span>
<span id="cb48-18"><a href="#cb48-18" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb48-19"><a href="#cb48-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> op <span class="op">:</span> ops<span class="op">)</span></span>
<span id="cb48-20"><a href="#cb48-20" aria-hidden="true" tabindex="-1"></a>    declare_op<span class="op">(</span>b, operand_type, op<span class="op">)</span>;</span>
<span id="cb48-21"><a href="#cb48-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb48-22"><a href="#cb48-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-23"><a href="#cb48-23" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> declare_arithmetic<span class="op">(</span>class_builder<span class="op">&amp;</span> b, type operand_type<span class="op">)</span> </span>
<span id="cb48-24"><a href="#cb48-24" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb48-25"><a href="#cb48-25" aria-hidden="true" tabindex="-1"></a>  <span class="co">// assuming math_compound and math_op are arrays containing the appropriate operator_kind </span></span>
<span id="cb48-26"><a href="#cb48-26" aria-hidden="true" tabindex="-1"></a>  declare_operators<span class="op">(</span>b, operand_type, math_compound<span class="op">)</span>; </span>
<span id="cb48-27"><a href="#cb48-27" aria-hidden="true" tabindex="-1"></a>  declare_operators<span class="op">(</span>b, operand_type, math_op<span class="op">)</span>;</span>
<span id="cb48-28"><a href="#cb48-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb48-29"><a href="#cb48-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-30"><a href="#cb48-30" aria-hidden="true" tabindex="-1"></a><span class="co">// usage... </span></span>
<span id="cb48-31"><a href="#cb48-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-32"><a href="#cb48-32" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, <span class="dt">unsigned</span> N<span class="op">&gt;</span></span>
<span id="cb48-33"><a href="#cb48-33" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> vec </span>
<span id="cb48-34"><a href="#cb48-34" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb48-35"><a href="#cb48-35" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span>operator_kind Op<span class="op">&gt;</span></span>
<span id="cb48-36"><a href="#cb48-36" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>is_compound_assign<span class="op">(</span>Op<span class="op">))</span></span>
<span id="cb48-37"><a href="#cb48-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span><span class="op">&amp;</span> apply_op<span class="op">(</span><span class="kw">const</span> vec<span class="op">&lt;</span>T, N<span class="op">&gt;&amp;</span> o<span class="op">)</span></span>
<span id="cb48-38"><a href="#cb48-38" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb48-39"><a href="#cb48-39" aria-hidden="true" tabindex="-1"></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>; k <span class="op">&lt;</span> N; <span class="op">++</span>k<span class="op">)</span></span>
<span id="cb48-40"><a href="#cb48-40" aria-hidden="true" tabindex="-1"></a>      <span class="op">(%</span>make_operator_expr<span class="op">(</span>Op, <span class="op">^(</span>data<span class="op">[</span>k<span class="op">])</span>, <span class="op">^(</span>o<span class="op">.</span>data<span class="op">[</span>k<span class="op">])))</span>;</span>
<span id="cb48-41"><a href="#cb48-41" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>;</span>
<span id="cb48-42"><a href="#cb48-42" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb48-43"><a href="#cb48-43" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-44"><a href="#cb48-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span>operator_kind Op<span class="op">&gt;</span></span>
<span id="cb48-45"><a href="#cb48-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <span class="op">(</span><span class="kw">not</span> std<span class="op">::</span>meta<span class="op">::</span>is_compound_assign<span class="op">(</span>Op<span class="op">))</span></span>
<span id="cb48-46"><a href="#cb48-46" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> apply_op<span class="op">(</span><span class="kw">const</span> vec<span class="op">&lt;</span>T, N<span class="op">&gt;&amp;</span> o<span class="op">)</span> <span class="kw">const</span> </span>
<span id="cb48-47"><a href="#cb48-47" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb48-48"><a href="#cb48-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> Res <span class="op">{*</span><span class="kw">this</span><span class="op">}</span>;</span>
<span id="cb48-49"><a href="#cb48-49" aria-hidden="true" tabindex="-1"></a>    <span class="op">(%</span> make_operator_expr<span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>compound_equivalent<span class="op">(</span>Op<span class="op">)</span>, <span class="op">^(</span>Res<span class="op">)</span>, <span class="op">^(</span>o<span class="op">))</span> <span class="op">)</span>;</span>
<span id="cb48-50"><a href="#cb48-50" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> Res;</span>
<span id="cb48-51"><a href="#cb48-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb48-52"><a href="#cb48-52" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-53"><a href="#cb48-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span><span class="kw">const</span> vec<span class="op">&lt;</span>T, N<span class="op">&gt;&amp;</span> o<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb48-54"><a href="#cb48-54" aria-hidden="true" tabindex="-1"></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>; k <span class="op">&lt;</span> N; <span class="op">++</span>k<span class="op">)</span></span>
<span id="cb48-55"><a href="#cb48-55" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(</span>data<span class="op">[</span>k<span class="op">]</span> <span class="op">!=</span> o<span class="op">.</span>data<span class="op">[</span>k<span class="op">])</span></span>
<span id="cb48-56"><a href="#cb48-56" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb48-57"><a href="#cb48-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb48-58"><a href="#cb48-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb48-59"><a href="#cb48-59" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-60"><a href="#cb48-60" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">!=(</span><span class="kw">const</span> vec<span class="op">&lt;</span>T, N<span class="op">&gt;&amp;</span> o<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb48-61"><a href="#cb48-61" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">!(*</span><span class="kw">this</span> <span class="op">==</span> o<span class="op">)</span>;</span>
<span id="cb48-62"><a href="#cb48-62" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb48-63"><a href="#cb48-63" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-64"><a href="#cb48-64" aria-hidden="true" tabindex="-1"></a>  T data<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb48-65"><a href="#cb48-65" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb48-66"><a href="#cb48-66" aria-hidden="true" tabindex="-1"></a>  <span class="op">%</span>declare_arithmetic<span class="op">(</span> <span class="op">^</span><span class="kw">const</span> vec<span class="op">&amp;</span> <span class="op">)</span>;</span>
<span id="cb48-67"><a href="#cb48-67" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Here we are using predicates over the kind of operator to pick the
correct overload.</p>
<h2 data-number="5.7" id="class-registration"><span class="header-section-number">5.7</span> Class registration<a href="#class-registration" class="self-link"></a></h2>
<p>Here is a simple utility to register a class constructor in a map.
The registrar must be a type along the lines of :</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Key, <span class="kw">class</span> Base<span class="op">&gt;</span></span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> basic_class_register</span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb49-4"><a href="#cb49-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> Ctor <span class="op">=</span> Base<span class="op">*(*)()</span>;</span>
<span id="cb49-5"><a href="#cb49-5" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unordered_map<span class="op">&lt;</span>Key, Ctor<span class="op">&gt;</span> ctor_map;</span>
<span id="cb49-6"><a href="#cb49-6" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb49-7"><a href="#cb49-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span> <span class="op">:</span> </span>
<span id="cb49-8"><a href="#cb49-8" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb49-9"><a href="#cb49-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> base_t <span class="op">=</span> Base;</span>
<span id="cb49-10"><a href="#cb49-10" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb49-11"><a href="#cb49-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb49-12"><a href="#cb49-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> emplace<span class="op">(</span>Key key<span class="op">)</span> <span class="op">{</span></span>
<span id="cb49-13"><a href="#cb49-13" aria-hidden="true" tabindex="-1"></a>    ctor_map<span class="op">.</span>emplace<span class="op">(</span> key, <span class="op">+[]</span> <span class="op">()</span> <span class="op">-&gt;</span> Base<span class="op">*</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">new</span> T<span class="op">{}</span>; <span class="op">}</span> <span class="op">)</span>;</span>
<span id="cb49-14"><a href="#cb49-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb49-15"><a href="#cb49-15" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb49-16"><a href="#cb49-16" aria-hidden="true" tabindex="-1"></a>  Base<span class="op">*</span> create<span class="op">(</span>Key key<span class="op">)</span> <span class="op">{</span></span>
<span id="cb49-17"><a href="#cb49-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> it <span class="op">=</span> ctor_map<span class="op">.</span>find<span class="op">(</span>key<span class="op">)</span>;</span>
<span id="cb49-18"><a href="#cb49-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>it <span class="op">==</span> ctor_map<span class="op">.</span>end<span class="op">())</span></span>
<span id="cb49-19"><a href="#cb49-19" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">nullptr</span>;</span>
<span id="cb49-20"><a href="#cb49-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> it<span class="op">-&gt;</span>second<span class="op">()</span>;</span>
<span id="cb49-21"><a href="#cb49-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb49-22"><a href="#cb49-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb49-23"><a href="#cb49-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb49-24"><a href="#cb49-24" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Base <span class="op">{</span></span>
<span id="cb49-25"><a href="#cb49-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">virtual</span> <span class="op">~</span>Base<span class="op">()</span> <span class="op">{}</span></span>
<span id="cb49-26"><a href="#cb49-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb49-27"><a href="#cb49-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb49-28"><a href="#cb49-28" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">static</span> basic_class_register<span class="op">&lt;</span>std<span class="op">::</span>string, Base<span class="op">&gt;</span> registrar;</span></code></pre></div>
<p>Then, a class declaration inheriting from Base can be registered via
:</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span>register_class<span class="op">(^</span>registrar, <span class="op">^</span>Derived<span class="op">)</span>;</span></code></pre></div>
<p>We can also register the classes contained in a namespace or a class
via :</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> ns <span class="op">{</span></span>
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> A <span class="op">:</span> Base <span class="op">{}</span>;</span>
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> B <span class="op">:</span> Base <span class="op">{}</span>;</span>
<span id="cb51-4"><a href="#cb51-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb51-5"><a href="#cb51-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-6"><a href="#cb51-6" aria-hidden="true" tabindex="-1"></a><span class="op">%</span>register_classes<span class="op">(^</span>registrar, <span class="op">^</span>ns<span class="op">)</span>;</span></code></pre></div>
<p>The implementation is fairly simple : we inject a static variable
with a placeholder name so that the class registration is executed at
the beginning of the program. By default, we use the (qualified) name of
the class as key.</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> register_class<span class="op">(</span>namespace_builder<span class="op">&amp;</span> b, decl registrar, type cd, expr key<span class="op">)</span></span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>cd, registrar, key<span class="op">]</span> <span class="kw">namespace</span> </span>
<span id="cb52-4"><a href="#cb52-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb52-5"><a href="#cb52-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="dt">bool</span> _ <span class="op">=</span> <span class="op">((%</span>registrar<span class="op">).</span><span class="kw">template</span> emplace<span class="op">&lt;</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>cd<span class="op">)</span> <span class="op">&gt;(%</span>key<span class="op">)</span>, <span class="kw">true</span><span class="op">)</span>;</span>
<span id="cb52-6"><a href="#cb52-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb52-7"><a href="#cb52-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb52-8"><a href="#cb52-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb52-9"><a href="#cb52-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> register_class<span class="op">(</span>namespace_builder<span class="op">&amp;</span> b, decl registrar, type cd<span class="op">)</span></span>
<span id="cb52-10"><a href="#cb52-10" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb52-11"><a href="#cb52-11" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>meta<span class="op">::</span>stringstream os;</span>
<span id="cb52-12"><a href="#cb52-12" aria-hidden="true" tabindex="-1"></a>  os <span class="op">&lt;&lt;</span> cd;</span>
<span id="cb52-13"><a href="#cb52-13" aria-hidden="true" tabindex="-1"></a>  register_class<span class="op">(</span>b, registrar, cd, make_literal_expr<span class="op">(</span>os<span class="op">))</span>;</span>
<span id="cb52-14"><a href="#cb52-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code class="sourceCode cpp">register_classes</code> function
traverse a namespace or class and register all the classes that inherit
from <code class="sourceCode cpp">base_t</code> declared by the
registrar :</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> register_classes<span class="op">(</span>namespace_builder<span class="op">&amp;</span> b, decl registrar, decl source<span class="op">)</span></span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> base <span class="op">=</span> type_of<span class="op">(*</span>begin<span class="op">(</span>lookup<span class="op">(</span>registrar, <span class="st">&quot;base_t&quot;</span><span class="op">)))</span>;</span>
<span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a>  ensure<span class="op">(</span>is_namespace<span class="op">(</span>source<span class="op">)</span> <span class="op">||</span> is_class<span class="op">(</span>source<span class="op">)</span>, <span class="st">&quot;source must a class or namespace&quot;</span><span class="op">)</span>;</span>
<span id="cb53-6"><a href="#cb53-6" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb53-7"><a href="#cb53-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> d <span class="op">:</span> children<span class="op">(</span>source<span class="op">))</span></span>
<span id="cb53-8"><a href="#cb53-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb53-9"><a href="#cb53-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>is_class<span class="op">(</span>d<span class="op">)</span> <span class="op">&amp;&amp;</span> is_derived_from<span class="op">(</span>type_of<span class="op">(</span>d<span class="op">)</span>, base<span class="op">))</span></span>
<span id="cb53-10"><a href="#cb53-10" aria-hidden="true" tabindex="-1"></a>      register_class<span class="op">(</span>b, registrar, d<span class="op">)</span>;</span>
<span id="cb53-11"><a href="#cb53-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb53-12"><a href="#cb53-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.8" id="enum-flagsum-generation"><span class="header-section-number">5.8</span> Enum flagsum generation<a href="#enum-flagsum-generation" class="self-link"></a></h2>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="op">%</span>declare_flagsum<span class="op">(</span><span class="st">&quot;MyFlagSum&quot;</span>, <span class="op">{</span><span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;c&quot;</span><span class="op">})</span>;</span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a><span class="co">// Produce the code : </span></span>
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> MyFlagSum <span class="op">{</span></span>
<span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a>  a <span class="op">=</span> <span class="dv">1</span>, b <span class="op">=</span> <span class="dv">2</span>, c <span class="op">=</span> <span class="dv">4</span></span>
<span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb54-8"><a href="#cb54-8" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> MyFlagSum <span class="kw">operator</span><span class="op">|(</span>MyFlagSum a, MyFlagSum b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb54-9"><a href="#cb54-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">(</span>MyFlagSum<span class="op">)</span> <span class="op">(</span>std<span class="op">::</span>to_underlying<span class="op">(</span>a<span class="op">)</span> <span class="op">|</span> std<span class="op">::</span>to_underlying<span class="op">(</span>b<span class="op">))</span>;</span>
<span id="cb54-10"><a href="#cb54-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This is an interesting use case, because we want to inject a
declaration (operator |) which uses the name of the enum we just
injected. Because we have no mechanism yet to do this, we first inject
the enumeration, then use <code class="sourceCode cpp">lookup</code> to
retrieve it, and perform a second injection for the operator.</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_flagsum_constants<span class="op">(</span>enum_builder<span class="op">&amp;</span> b, <span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>identifier<span class="op">&gt;&amp;</span> ids<span class="op">)</span> </span>
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> k <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> id <span class="op">:</span> ids<span class="op">)</span> </span>
<span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb55-6"><a href="#cb55-6" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="kw">enum</span> <span class="op">[</span>id, k<span class="op">]</span> <span class="op">{</span> <span class="op">%</span>name<span class="op">(</span>id<span class="op">)</span> <span class="op">=</span> k <span class="op">}</span>;</span>
<span id="cb55-7"><a href="#cb55-7" aria-hidden="true" tabindex="-1"></a>    k <span class="op">*=</span> <span class="dv">2</span>;</span>
<span id="cb55-8"><a href="#cb55-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb55-9"><a href="#cb55-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb55-10"><a href="#cb55-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb55-11"><a href="#cb55-11" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> declare_flagsum<span class="op">(</span>namespace_builder<span class="op">&amp;</span> b, identifier Name, std<span class="op">::</span>vector<span class="op">&lt;</span>identifier<span class="op">&gt;</span> ids<span class="op">)</span> </span>
<span id="cb55-12"><a href="#cb55-12" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb55-13"><a href="#cb55-13" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[&amp;</span>ids<span class="op">]</span> <span class="kw">namespace</span></span>
<span id="cb55-14"><a href="#cb55-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb55-15"><a href="#cb55-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> <span class="op">%</span>name<span class="op">(</span>Name<span class="op">)</span> </span>
<span id="cb55-16"><a href="#cb55-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb55-17"><a href="#cb55-17" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span>gen_flagsum_constants<span class="op">(</span>ids<span class="op">)</span></span>
<span id="cb55-18"><a href="#cb55-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb55-19"><a href="#cb55-19" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb55-20"><a href="#cb55-20" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb55-21"><a href="#cb55-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> Enum <span class="op">=</span> <span class="op">*</span>begin<span class="op">(</span>lookup<span class="op">(</span>decl_of<span class="op">(</span>b<span class="op">)</span>, Name<span class="op">))</span>;</span>
<span id="cb55-22"><a href="#cb55-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> EnumTy <span class="op">=</span> type_of<span class="op">(</span>Enum<span class="op">)</span>;</span>
<span id="cb55-23"><a href="#cb55-23" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb55-24"><a href="#cb55-24" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^[</span>EnumTy<span class="op">]</span> <span class="kw">namespace</span> <span class="op">{</span></span>
<span id="cb55-25"><a href="#cb55-25" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>EnumTy<span class="op">)</span> <span class="kw">operator</span><span class="op">|</span> <span class="op">(%</span><span class="kw">typename</span><span class="op">(</span>EnumTy<span class="op">)</span> A, <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>EnumTy<span class="op">)</span> B<span class="op">)</span> <span class="op">{</span></span>
<span id="cb55-26"><a href="#cb55-26" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="op">(%</span><span class="kw">typename</span><span class="op">(</span>EnumTy<span class="op">))</span> <span class="op">(</span>std<span class="op">::</span>to_underlying<span class="op">(</span>A<span class="op">)</span> <span class="op">|</span> std<span class="op">::</span>to_underlying<span class="op">(</span>B<span class="op">))</span>;</span>
<span id="cb55-27"><a href="#cb55-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb55-28"><a href="#cb55-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb55-29"><a href="#cb55-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.9" id="members-and-overload-set-lifting"><span class="header-section-number">5.9</span> Members and overload set
lifting<a href="#members-and-overload-set-lifting" class="self-link"></a></h2>
<p>Encapsulating members and overload sets in a callable is quite
straightforward, as declaration names and overload set can be passed as
template arguments. This would not be possible if names were
<code class="sourceCode cpp">string_view</code>/if overload sets used
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>.</p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>overload_set OS<span class="op">&gt;</span></span>
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> lift_overload_set <span class="op">{</span></span>
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="kw">operator</span><span class="op">()(</span>Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(%</span>OS<span class="op">)(</span><span class="kw">static_cast</span><span class="op">&lt;</span>Args<span class="op">&amp;&amp;&gt;(</span>args<span class="op">)...)</span>;</span>
<span id="cb56-6"><a href="#cb56-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb56-7"><a href="#cb56-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb56-8"><a href="#cb56-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb56-9"><a href="#cb56-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr lift<span class="op">(</span>overload_set os<span class="op">)</span> <span class="op">{</span></span>
<span id="cb56-10"><a href="#cb56-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>os<span class="op">]</span> <span class="op">(</span> lift_overload<span class="op">&lt;</span>os<span class="op">&gt;{}</span> <span class="op">)</span>;</span>
<span id="cb56-11"><a href="#cb56-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb56-12"><a href="#cb56-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb56-13"><a href="#cb56-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>name N<span class="op">&gt;</span></span>
<span id="cb56-14"><a href="#cb56-14" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> lift_member <span class="op">{</span></span>
<span id="cb56-15"><a href="#cb56-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb56-16"><a href="#cb56-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="kw">operator</span><span class="op">()(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> head, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb56-17"><a href="#cb56-17" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> head<span class="op">.%(</span>N<span class="op">)(</span><span class="kw">static_cast</span><span class="op">&lt;</span>Args<span class="op">&amp;&amp;&gt;(</span>args<span class="op">)...)</span>;</span>
<span id="cb56-18"><a href="#cb56-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb56-19"><a href="#cb56-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb56-20"><a href="#cb56-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb56-21"><a href="#cb56-21" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr lift<span class="op">(</span>name n<span class="op">)</span> <span class="op">{</span> <span class="co">// lift a member named n</span></span>
<span id="cb56-22"><a href="#cb56-22" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>n<span class="op">]</span> <span class="op">(</span> lift_member<span class="op">&lt;</span>n<span class="op">&gt;{}</span> <span class="op">)</span>;</span>
<span id="cb56-23"><a href="#cb56-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Usage :</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span> vecs <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>sort<span class="op">(</span> vecs, <span class="op">%</span>lift<span class="op">(</span><span class="st">&quot;size&quot;</span><span class="op">)</span> <span class="op">)</span>;</span></code></pre></div>
<h2 data-number="5.10" id="ensure-replacement-for-assert"><span class="header-section-number">5.10</span>
<code class="sourceCode cpp">ensure</code> : replacement for assert<a href="#ensure-replacement-for-assert" class="self-link"></a></h2>
<p>Here we implement a simple, hygienic assert macro replacement, which
is able to adapt to whether or not it is invoked in a
consteval/constexpr function. We can emit an error at compile-time using
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>error</code>.</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr make_error_string<span class="op">(</span>expr e, source_location loc, expr error_msg, <span class="dt">bool</span> PrintLoc <span class="op">=</span> <span class="kw">true</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>meta<span class="op">::</span>stringstream ss;</span>
<span id="cb58-3"><a href="#cb58-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>PrintLoc<span class="op">)</span></span>
<span id="cb58-4"><a href="#cb58-4" aria-hidden="true" tabindex="-1"></a>    ss <span class="op">&lt;&lt;</span> loc <span class="op">&lt;&lt;</span> <span class="st">&quot;: &quot;</span>;</span>
<span id="cb58-5"><a href="#cb58-5" aria-hidden="true" tabindex="-1"></a>  ss <span class="op">&lt;&lt;</span> <span class="st">&quot;Assertion failed (&quot;</span> <span class="op">&lt;&lt;</span> e <span class="op">&lt;&lt;</span> <span class="st">&quot;)&quot;</span>;</span>
<span id="cb58-6"><a href="#cb58-6" aria-hidden="true" tabindex="-1"></a>  ss <span class="op">&lt;&lt;</span> <span class="st">&quot; : &quot;</span> <span class="op">&lt;&lt;</span> error_msg <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb58-7"><a href="#cb58-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> make_literal_expr<span class="op">(</span>ss<span class="op">)</span>;</span>
<span id="cb58-8"><a href="#cb58-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb58-9"><a href="#cb58-9" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb58-10"><a href="#cb58-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_consteval_failure<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr e, source_location loc, expr msg<span class="op">)</span> </span>
<span id="cb58-11"><a href="#cb58-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb58-12"><a href="#cb58-12" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>e, loc, msg<span class="op">]</span> </span>
<span id="cb58-13"><a href="#cb58-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb58-14"><a href="#cb58-14" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>meta<span class="op">::</span>error<span class="op">(</span>loc, <span class="op">%</span>make_error_string<span class="op">(</span>e, loc, msg, <span class="kw">false</span><span class="op">))</span>;</span>
<span id="cb58-15"><a href="#cb58-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb58-16"><a href="#cb58-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb58-17"><a href="#cb58-17" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb58-18"><a href="#cb58-18" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_runtime_failure<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr e, source_location loc, expr msg<span class="op">)</span></span>
<span id="cb58-19"><a href="#cb58-19" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb58-20"><a href="#cb58-20" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>e, loc, msg<span class="op">]</span> </span>
<span id="cb58-21"><a href="#cb58-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb58-22"><a href="#cb58-22" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="op">%</span>make_error_string<span class="op">(</span>e, loc, msg<span class="op">)</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb58-23"><a href="#cb58-23" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>abort<span class="op">()</span>;</span>
<span id="cb58-24"><a href="#cb58-24" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb58-25"><a href="#cb58-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb58-26"><a href="#cb58-26" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb58-27"><a href="#cb58-27" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> gen_failure<span class="op">(</span>function_builder<span class="op">&amp;</span> b, source_location loc, expr e, expr msg<span class="op">)</span> </span>
<span id="cb58-28"><a href="#cb58-28" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb58-29"><a href="#cb58-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> fn <span class="op">=</span> decl_of<span class="op">(</span>b<span class="op">)</span>;</span>
<span id="cb58-30"><a href="#cb58-30" aria-hidden="true" tabindex="-1"></a>  </span>
<span id="cb58-31"><a href="#cb58-31" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>is_consteval<span class="op">(</span>fn<span class="op">))</span></span>
<span id="cb58-32"><a href="#cb58-32" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb58-33"><a href="#cb58-33" aria-hidden="true" tabindex="-1"></a>    gen_consteval_failure<span class="op">(</span>b, e, loc, msg<span class="op">)</span>;</span>
<span id="cb58-34"><a href="#cb58-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb58-35"><a href="#cb58-35" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>is_constexpr<span class="op">(</span>fn<span class="op">))</span></span>
<span id="cb58-36"><a href="#cb58-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb58-37"><a href="#cb58-37" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>msg, e, loc<span class="op">]</span> </span>
<span id="cb58-38"><a href="#cb58-38" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb58-39"><a href="#cb58-39" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb58-40"><a href="#cb58-40" aria-hidden="true" tabindex="-1"></a>        <span class="op">%</span> gen_consteval_failure<span class="op">(</span>e, loc, msg<span class="op">)</span>;</span>
<span id="cb58-41"><a href="#cb58-41" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb58-42"><a href="#cb58-42" aria-hidden="true" tabindex="-1"></a>      <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb58-43"><a href="#cb58-43" aria-hidden="true" tabindex="-1"></a>        <span class="op">%</span> gen_runtime_failure<span class="op">(</span>e, loc, msg<span class="op">)</span>;</span>
<span id="cb58-44"><a href="#cb58-44" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb58-45"><a href="#cb58-45" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb58-46"><a href="#cb58-46" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb58-47"><a href="#cb58-47" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span></span>
<span id="cb58-48"><a href="#cb58-48" aria-hidden="true" tabindex="-1"></a>    gen_runtime_failure<span class="op">(</span>b, e, loc, msg<span class="op">)</span>;</span>
<span id="cb58-49"><a href="#cb58-49" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb58-50"><a href="#cb58-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb58-51"><a href="#cb58-51" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> ensure<span class="op">(</span>function_builder<span class="op">&amp;</span> b, expr e, <span class="kw">const</span> <span class="dt">char</span><span class="op">*</span> message<span class="op">)</span> </span>
<span id="cb58-52"><a href="#cb58-52" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb58-53"><a href="#cb58-53" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>e, msg <span class="op">=</span> make_literal_expr<span class="op">(</span>message<span class="op">)</span>, loc <span class="op">=</span> location<span class="op">(</span>b<span class="op">)]</span> </span>
<span id="cb58-54"><a href="#cb58-54" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb58-55"><a href="#cb58-55" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(!%</span>e<span class="op">)</span></span>
<span id="cb58-56"><a href="#cb58-56" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb58-57"><a href="#cb58-57" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span> impl<span class="op">::</span>gen_failure<span class="op">(</span>loc, e, msg<span class="op">)</span>; </span>
<span id="cb58-58"><a href="#cb58-58" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb58-59"><a href="#cb58-59" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb58-60"><a href="#cb58-60" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="5.11" id="cloning-types-logged-class"><span class="header-section-number">5.11</span> Cloning types : logged class<a href="#cloning-types-logged-class" class="self-link"></a></h2>
<p>As P2237 points out (in section 7.2.6 : Injecting parameters),
injecting functions or template parameters with fragments is a
challenge.</p>
<p>In this section we explore a possible solution, which we have yet to
fully implement.</p>
<p>Generating a function prototype with an arity determined from input
values could be done with range expansions, which are needed in other
places like expression construction anyway :</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> inject_foo<span class="op">(</span>type_list tl<span class="op">)</span> <span class="op">{</span></span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">^</span> <span class="op">[</span>tl<span class="op">]</span> <span class="kw">namespace</span> <span class="op">{</span></span>
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> foo<span class="op">(</span> <span class="op">%...</span><span class="kw">typename</span><span class="op">(</span>tl<span class="op">)...</span> params <span class="op">)</span>;</span>
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb59-5"><a href="#cb59-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>But this doesn’t let us specify default arguments, which is a big
drawback for the purpose of cloning an interface.</p>
<p>One possible solution is injection statements within a function
parameter list :</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> inject_params<span class="op">(</span>function_parameters_builder<span class="op">&amp;)</span> <span class="op">{</span></span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a>  <span class="co">// placeholder syntax for function parameter list fragment </span></span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^(|</span> int x <span class="op">|)</span>;</span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a>  b <span class="op">&lt;&lt;</span> <span class="op">^(|</span> <span class="dt">float</span> y <span class="op">=</span> <span class="fl">1.2</span> <span class="op">|)</span>;</span>
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span> <span class="op">%|</span>inject_params<span class="op">()|</span> <span class="op">)</span>;</span></code></pre></div>
<p>Here, the placeholder syntax <code class="sourceCode cpp"><span class="op">%|</span> <em>constant-expression</em> <span class="op">|</span></code>
produce an injection statement within a parameter list. Unfortunately,
we need a different syntax than expression injection here, otherwise we
have no way to know if this is a function declaration or a variable
whose initialiser is injected.</p>
<p>Parameters injection goes hand in hand with the ability to retrieve
the parameters in a context where we do not yet know their names. In
this exploratory exemple, this is done by the expression <code class="sourceCode cpp">parameters_of<span class="op">(^</span><span class="kw">this</span><span class="op">)</span></code>,
where <code class="sourceCode cpp"><span class="op">^</span><span class="kw">this</span></code>
results in a reflection of the declaration in which it appears.</p>
<p>With those mechanisms, we can implement the
<code class="sourceCode cpp">LoggingVector</code> class described in
P3294 :</p>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> type transpose_obj_type<span class="op">(</span>type new_class, type old_obj_ty<span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> new_obj_ty <span class="op">=</span> new_class;</span>
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>is_const<span class="op">(</span>remove_reference<span class="op">(</span>old_obj_ty<span class="op">)))</span></span>
<span id="cb61-4"><a href="#cb61-4" aria-hidden="true" tabindex="-1"></a>    new_obj_ty <span class="op">=</span> add_const<span class="op">(</span>new_obj_ty<span class="op">)</span>;</span>
<span id="cb61-5"><a href="#cb61-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>is_lvalue_reference<span class="op">(</span>old_obj_ty<span class="op">))</span></span>
<span id="cb61-6"><a href="#cb61-6" aria-hidden="true" tabindex="-1"></a>    new_obj_ty <span class="op">=</span> add_lvalue_reference<span class="op">(</span>new_obj_ty<span class="op">)</span>;</span>
<span id="cb61-7"><a href="#cb61-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>is_rvalue_reference<span class="op">(</span>old_obj_ty<span class="op">))</span></span>
<span id="cb61-8"><a href="#cb61-8" aria-hidden="true" tabindex="-1"></a>    new_obj_ty <span class="op">=</span> add_rvalue_reference<span class="op">(</span>new_obj_ty<span class="op">)</span>;</span>
<span id="cb61-9"><a href="#cb61-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> new_obj_ty;</span>
<span id="cb61-10"><a href="#cb61-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb61-11"><a href="#cb61-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-12"><a href="#cb61-12" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> clone_parameters<span class="op">(</span>function_parameters_builder<span class="op">&amp;</span> b, decl f, type new_class<span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-13"><a href="#cb61-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> p <span class="op">:</span> inner_parameters_of<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb61-14"><a href="#cb61-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb61-15"><a href="#cb61-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> ty <span class="op">=</span> type_of<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb61-16"><a href="#cb61-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>remove_cv_ref<span class="op">(</span>ty<span class="op">)</span> <span class="op">==</span> remove_cv_ref<span class="op">(</span>object_type<span class="op">(</span>f<span class="op">)))</span></span>
<span id="cb61-17"><a href="#cb61-17" aria-hidden="true" tabindex="-1"></a>      ty <span class="op">=</span> transpose_obj_type<span class="op">(</span>new_class, ty<span class="op">)</span>;</span>
<span id="cb61-18"><a href="#cb61-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(!</span>has_initializer<span class="op">(</span>p<span class="op">))</span></span>
<span id="cb61-19"><a href="#cb61-19" aria-hidden="true" tabindex="-1"></a>      b <span class="op">&lt;&lt;</span> <span class="op">^[</span>p, ty<span class="op">]</span> <span class="op">(|</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>ty<span class="op">)</span> <span class="op">%</span>name<span class="op">(</span>name_of<span class="op">(</span>p<span class="op">))</span> <span class="op">|)</span>;</span>
<span id="cb61-20"><a href="#cb61-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span></span>
<span id="cb61-21"><a href="#cb61-21" aria-hidden="true" tabindex="-1"></a>      b <span class="op">&lt;&lt;</span> <span class="op">^[</span>p, ty<span class="op">]</span> <span class="op">(|</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>ty<span class="op">)</span> <span class="op">%</span>name<span class="op">(</span>name_of<span class="op">(</span>p<span class="op">))</span> <span class="op">=</span> <span class="op">%</span>initializer<span class="op">(</span>p<span class="op">)</span> <span class="op">|)</span>;</span>
<span id="cb61-22"><a href="#cb61-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb61-23"><a href="#cb61-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb61-24"><a href="#cb61-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-25"><a href="#cb61-25" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr_list fwd_args<span class="op">(</span>decl_list params<span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-26"><a href="#cb61-26" aria-hidden="true" tabindex="-1"></a>  expr_list res; </span>
<span id="cb61-27"><a href="#cb61-27" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> p <span class="op">:</span> params<span class="op">)</span></span>
<span id="cb61-28"><a href="#cb61-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb61-29"><a href="#cb61-29" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> ty <span class="op">=</span> add_rvalue_reference<span class="op">(</span>type_of<span class="op">(</span>p<span class="op">))</span>;</span>
<span id="cb61-30"><a href="#cb61-30" aria-hidden="true" tabindex="-1"></a>    push_back<span class="op">(</span>res, <span class="op">^[</span>ty<span class="op">]</span> <span class="op">(</span><span class="kw">static_cast</span><span class="op">&lt;</span> <span class="op">%</span>ty <span class="op">&gt;(%</span>p<span class="op">))</span> <span class="op">)</span>;</span>
<span id="cb61-31"><a href="#cb61-31" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb61-32"><a href="#cb61-32" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> res;</span>
<span id="cb61-33"><a href="#cb61-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb61-34"><a href="#cb61-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-35"><a href="#cb61-35" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> expr to_string_lit<span class="op">(</span>name n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-36"><a href="#cb61-36" aria-hidden="true" tabindex="-1"></a>  stringstream ss;</span>
<span id="cb61-37"><a href="#cb61-37" aria-hidden="true" tabindex="-1"></a>  ss <span class="op">&lt;&lt;</span> n;</span>
<span id="cb61-38"><a href="#cb61-38" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> make_literal_expr<span class="op">(</span>ss<span class="op">)</span>;</span>
<span id="cb61-39"><a href="#cb61-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb61-40"><a href="#cb61-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb61-41"><a href="#cb61-41" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">void</span> clone_interface<span class="op">(</span>class_builder<span class="op">&amp;</span> b, decl d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-42"><a href="#cb61-42" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> f <span class="op">:</span> functions<span class="op">(</span>d<span class="op">))</span> </span>
<span id="cb61-43"><a href="#cb61-43" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb61-44"><a href="#cb61-44" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>is_static_member<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb61-45"><a href="#cb61-45" aria-hidden="true" tabindex="-1"></a>      <span class="cf">continue</span>;</span>
<span id="cb61-46"><a href="#cb61-46" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb61-47"><a href="#cb61-47" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> obj_ty <span class="op">=</span> transpose_obj_type<span class="op">(</span>type_of<span class="op">(</span>b<span class="op">)</span>, object_type<span class="op">(</span>f<span class="op">))</span>;</span>
<span id="cb61-48"><a href="#cb61-48" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb61-49"><a href="#cb61-49" aria-hidden="true" tabindex="-1"></a>    b <span class="op">&lt;&lt;</span> <span class="op">^</span> <span class="op">[</span>f, obj_ty<span class="op">]</span> <span class="kw">struct</span> T</span>
<span id="cb61-50"><a href="#cb61-50" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb61-51"><a href="#cb61-51" aria-hidden="true" tabindex="-1"></a>      <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>return_type<span class="op">(</span>f<span class="op">))</span> <span class="op">%</span>name<span class="op">(</span>name_of<span class="op">(</span>f<span class="op">))</span> <span class="op">(</span> <span class="kw">this</span> <span class="op">%</span><span class="kw">typename</span><span class="op">(</span>obj_ty<span class="op">)</span> self, <span class="op">%|</span>clone_parameters<span class="op">(</span>f, <span class="op">^</span>T<span class="op">)|</span> <span class="op">)</span> <span class="op">{</span></span>
<span id="cb61-52"><a href="#cb61-52" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">auto</span> args_list <span class="op">=</span> fwd_args<span class="op">(</span>parameters_of<span class="op">(^</span><span class="kw">this</span><span class="op">))</span>;</span>
<span id="cb61-53"><a href="#cb61-53" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;Calling {}&quot;</span>, <span class="op">%</span>to_string_lit<span class="op">(</span>name_of<span class="op">(</span>f<span class="op">)))</span>;</span>
<span id="cb61-54"><a href="#cb61-54" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> self<span class="op">.</span>impl<span class="op">.%(</span>name_of<span class="op">(</span>f<span class="op">))(</span> <span class="op">%...</span>args_list<span class="op">...</span> <span class="op">)</span>;</span>
<span id="cb61-55"><a href="#cb61-55" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb61-56"><a href="#cb61-56" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb61-57"><a href="#cb61-57" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb61-58"><a href="#cb61-58" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>For comparison, here is the equivalent code of P3294 :</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> LoggingVector <span class="op">{</span></span>
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span> impl;</span>
<span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb62-5"><a href="#cb62-5" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb62-6"><a href="#cb62-6" aria-hidden="true" tabindex="-1"></a>    LoggingVector<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span> v<span class="op">)</span> <span class="op">:</span> impl<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>v<span class="op">))</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb62-7"><a href="#cb62-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb62-8"><a href="#cb62-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb62-9"><a href="#cb62-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span>std<span class="op">::</span>meta<span class="op">::</span>info fun <span class="op">:</span> <span class="co">/* public, non-special member functions */</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb62-10"><a href="#cb62-10" aria-hidden="true" tabindex="-1"></a>            <span class="kw">auto</span> argument_list <span class="op">=</span> list_builder<span class="op">()</span>;</span>
<span id="cb62-11"><a href="#cb62-11" aria-hidden="true" tabindex="-1"></a>            <span class="cf">for</span> <span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">!=</span> parameters_of<span class="op">(</span>fun<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="cb62-12"><a href="#cb62-12" aria-hidden="true" tabindex="-1"></a>                argument_list <span class="op">+=</span> <span class="op">^{</span></span>
<span id="cb62-13"><a href="#cb62-13" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// we could get the nth parameter&#39;s type (we can&#39;t splice</span></span>
<span id="cb62-14"><a href="#cb62-14" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// the other function&#39;s parameters but we CAN query them)</span></span>
<span id="cb62-15"><a href="#cb62-15" aria-hidden="true" tabindex="-1"></a>                    <span class="co">// or we could just write decltype(p0)</span></span>
<span id="cb62-16"><a href="#cb62-16" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>\id<span class="op">(</span><span class="st">&quot;p&quot;</span>, i<span class="op">))&amp;&amp;&gt;(</span>\id<span class="op">(</span><span class="st">&quot;p&quot;</span>, i<span class="op">))</span></span>
<span id="cb62-17"><a href="#cb62-17" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span>;</span>
<span id="cb62-18"><a href="#cb62-18" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb62-19"><a href="#cb62-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb62-20"><a href="#cb62-20" aria-hidden="true" tabindex="-1"></a>            queue_injection<span class="op">(^{</span></span>
<span id="cb62-21"><a href="#cb62-21" aria-hidden="true" tabindex="-1"></a>                \tokens<span class="op">(</span>make_decl_of<span class="op">(</span>fun, <span class="st">&quot;p&quot;</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb62-22"><a href="#cb62-22" aria-hidden="true" tabindex="-1"></a>                    std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;Calling {}&quot;</span>, \<span class="op">(</span>name_of<span class="op">(</span>fun<span class="op">)))</span>;</span>
<span id="cb62-23"><a href="#cb62-23" aria-hidden="true" tabindex="-1"></a>                    <span class="cf">return</span> impl<span class="op">.[:</span>\<span class="op">(</span>fun<span class="op">):](</span> <span class="op">[:</span>\<span class="op">(</span>argument_list<span class="op">):]</span> <span class="op">)</span>;</span>
<span id="cb62-24"><a href="#cb62-24" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb62-25"><a href="#cb62-25" aria-hidden="true" tabindex="-1"></a>            <span class="op">})</span>;</span>
<span id="cb62-26"><a href="#cb62-26" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb62-27"><a href="#cb62-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb62-28"><a href="#cb62-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>It relies on a <code class="sourceCode cpp">make_decl_of</code>
function which construct the token sequence necessary to clone a
function. We could also pretend to have such a function (taking a
function fragment as argument) but it must be pointed out that its
implementation would be perhaps more difficult, as we cannot factor out
declaration specifiers such as
<code class="sourceCode cpp"><span class="kw">virtual</span></code> or
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
which is trivial with tokens manipulation.</p>
<p>Nevertheless, we are able to map the old class type to the new one,
which enables us to declare e.g. constructors or
<code class="sourceCode cpp">swap</code>, which P3294 cannot do.</p>
<h1 data-number="6" id="future-work"><span class="header-section-number">6</span> Future work<a href="#future-work" class="self-link"></a></h1>
<p>In many of these exemples, we have to pass down reflection of local
declarations to our meta-programming algorithms. This is where P2296 and
P3294 have an ergonomic advantage. The first, because <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>
allows to refers to local declarations within a code generating
statement (arguably, this is not a matter of model : our design could
include <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>).
The second, because tokens sequences are unchecked, the declarations
references will be resolved at the point of injection. More work is
needed to find a solution to this problem – perhaps <code class="sourceCode cpp"><span class="kw">template</span> <span class="cf">for</span></code>
is enough.</p>
<p>Adjacent to this problem is better support for two phase lookup, and
referring to declarations whose name is injected. Currently this is done
manually (see enum flagsum example), but ultimately we would like to be
able to refer to declarations via an injected name.</p>
<p>Finally, constructing template and functions parameters lists, as
well as injecting constructors initialisers, is for now unsupported.
This is a domain where tokens injection has an advantage, as it is
allows complete freedom with little specification.</p>
<p>While this design and its implementation are still a work in
progress, everything we have discussed in this paper, unless otherwise
specified, has been implemented. We hope to show that a fragment based
meta-programming model along a “reasonably typed” reflection API is a
viable avenue for standard C++.</p>
<h1 data-number="7" id="bibliography"><span class="header-section-number">7</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P2237R0" class="csl-entry" role="doc-biblioentry">
[P2237R0] Andrew Sutton. 2020-10-15. Metaprogramming. <a href="https://wg21.link/p2237r0"><div class="csl-block">https://wg21.link/p2237r0</div></a>
</div>
<div id="ref-P2996R5" class="csl-entry" role="doc-biblioentry">
[P2996R5] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-08-14. Reflection for
C++26. <a href="https://wg21.link/p2996r5"><div class="csl-block">https://wg21.link/p2996r5</div></a>
</div>
<div id="ref-P3294R1" class="csl-entry" role="doc-biblioentry">
[P3294R1] Barry Revzin, Andrei Alexandrescu, Daveed Vandevoorde.
2024-07-16. Code Injection with Token Sequences. <a href="https://wg21.link/p3294r1"><div class="csl-block">https://wg21.link/p3294r1</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
