<!DOCTYPE html>
<!-- saved from url=(0059)https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html -->
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  
  <meta name="generator" content="mpark/wg21">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
  <meta name="dcterms.date" content="2024-09-04">
  <title>Attributes reflection</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]-->
<style>
      @keyframes rotate360 {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    
        @font-face {
            font-family: 'Amazon Ember';
            src: url("chrome-extension://cgdjpilhipecahhcilnafpblkieebhea/fonts/AmazonEmber_Rg.ttf");
            font-weight: normal;
            font-style: normal;
            font-display: swap; 
        }
        @font-face {
            font-family: 'Amazon Ember';
            src: url("chrome-extension://cgdjpilhipecahhcilnafpblkieebhea/fonts/AmazonEmber_Bd.ttf");
            font-weight: bold;
            font-style: normal;
        }
    </style><style>
      @keyframes rotate360 {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    
        @font-face {
            font-family: 'Amazon Ember';
            src: url("chrome-extension://cgdjpilhipecahhcilnafpblkieebhea/fonts/AmazonEmber_Rg.ttf");
            font-weight: normal;
            font-style: normal;
            font-display: swap; 
        }
        @font-face {
            font-family: 'Amazon Ember';
            src: url("chrome-extension://cgdjpilhipecahhcilnafpblkieebhea/fonts/AmazonEmber_Bd.ttf");
            font-weight: bold;
            font-style: normal;
        }
    </style></head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Attributes
reflection</h1>
<table style="border:none;float:right">
  <tbody><tr>
    <td>Document #:</td>
    <td><a href="https://wg21.link/D3385R0" class="wg21_link">P3385R0</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-09-04</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>
      sg7<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Aurelien Cassagnes<br>&lt;<a href="mailto:aurelien.cassagnes@gmail.com" class="email">aurelien.cassagnes@gmail.com</a>&gt;<br>
      Roman Khoroshikh<br>&lt;<a href="mailto:rkhoroshikh@bloomberg.net" class="email">rkhoroshikh@bloomberg.net</a>&gt;<br>
      Anders Johansson<br>&lt;<a href="mailto:ajohansson12@bloomberg.net" class="email">ajohansson12@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</tbody></table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#earlier-work" id="toc-earlier-work"><span class="toc-section-number">1.1</span> Earlier work<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#scope" id="toc-scope"><span class="toc-section-number">1.2</span> Scope<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#optionality-rule" id="toc-optionality-rule"><span class="toc-section-number">1.3</span> Optionality
rule<span></span></a></li>
</ul></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#proposed-features" id="toc-proposed-features"><span class="toc-section-number">2</span> Proposed Features<span></span></a>
<ul>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#stdmetainfo" id="toc-stdmetainfo"><span class="toc-section-number">2.1</span>
std::meta::info<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#reflection-operator" id="toc-reflection-operator"><span class="toc-section-number">2.2</span> Reflection
operator<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#splicers" id="toc-splicers"><span class="toc-section-number">2.3</span> Splicers<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#metafunctions" id="toc-metafunctions"><span class="toc-section-number">2.4</span>
Metafunctions<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#queries" id="toc-queries"><span class="toc-section-number">2.5</span> Queries<span></span></a></li>
</ul></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">3</span> Proposed wording<span></span></a>
<ul>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#language" id="toc-language"><span class="toc-section-number">3.1</span> Language<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#library" id="toc-library"><span class="toc-section-number">3.2</span> Library<span></span></a></li>
</ul></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#discussion" id="toc-discussion"><span class="toc-section-number">4</span> Discussion<span></span></a></li>
<li><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#bibliography" id="toc-bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#introduction" class="self-link"></a></h1>
<p>Attributes are used to great extent and there likely will be
attributes added as the language evolves.<br>
What is missing as reflection makes its way into our standard, is a way
for generic code to look into the attributes appertaining to an entity.
This is what the proposal here aims to tackle.<br>
</p>
<p>A motivating example is the following</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> Result <span class="op">{</span></span>
<span id="cb1-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-3" aria-hidden="true" tabindex="-1"></a>        success,</span>
<span id="cb1-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-4" aria-hidden="true" tabindex="-1"></a>        warn,</span>
<span id="cb1-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-5" aria-hidden="true" tabindex="-1"></a>        fail,</span>
<span id="cb1-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb1-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> StrictNormalize <span class="op">{</span></span>
<span id="cb1-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()</span> <span class="op">(</span>Result status<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-10" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> status <span class="op">==</span> Result<span class="op">::</span>success;</span>
<span id="cb1-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb1-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb1-13"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-14"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-14" 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="cb1-15"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> </span><span class="op">^</span><span class="at">F </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span> <span class="co">// expand into [[ nodiscard ]]</span></span>
<span id="cb1-16"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> transform<span class="op">(</span><span class="kw">auto</span><span class="op">...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-17"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> F<span class="op">()(</span>args<span class="op">...)</span>;</span>
<span id="cb1-18"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb1-19"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-20" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-21"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-21" aria-hidden="true" tabindex="-1"></a>        transform<span class="op">&lt;</span>StrictNormalize<span class="op">&gt;(</span>Result<span class="op">::</span>success<span class="op">)</span>; <span class="co">// warning on "nodiscard"</span></span>
<span id="cb1-22"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-22" aria-hidden="true" tabindex="-1"></a>        <span class="dt">bool</span> isOk <span class="op">=</span> transform<span class="op">&lt;</span>StrictNormalize<span class="op">&gt;(</span>Result<span class="op">::</span>success<span class="op">)</span>; <span class="co">// OK</span></span>
<span id="cb1-23"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-24"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb1-24" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Here <code class="sourceCode cpp">transform</code> looks into the
attributes attached to the callable
<code class="sourceCode cpp">F</code>, and recovers the <code class="sourceCode cpp"><span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span></code>
attribute that appertained originally to
<code class="sourceCode cpp">StrictNormalize</code> declaration.<br>
</p>
<p>We expect number of applications for attribute introspection to
happen in the context of code injection <span class="citation" data-cites="P2237R0">[<a href="https://wg21.link/p2237r0" role="doc-biblioref">P2237R0</a>]</span> where one may want to skip over
<code class="sourceCode cpp"><span class="op">[[</span><span class="at">deprecated</span><span class="op">]]</span></code>
members for example. Following example demonstrates skipping over
deprecated members</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> User <span class="op">{</span></span>
<span id="cb2-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">deprecated</span><span class="op">]]</span> std<span class="op">::</span>string name;</span>
<span id="cb2-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string uuidv5;</span>
<span id="cb2-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">deprecated</span><span class="op">]]</span> std<span class="op">::</span>string country;</span>
<span id="cb2-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string countryIsoCode;</span>
<span id="cb2-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb2-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-9" 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="cb2-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</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> liveMembers<span class="op">(</span><span class="kw">const</span> T<span class="op">&amp;</span> user<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-11" 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> liveMembers;</span>
<span id="cb2-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> deprecatedAttribute <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>attributes_of<span class="op">(^[[</span><span class="at">deprecated</span><span class="op">]])[</span><span class="dv">0</span><span class="op">]</span>;</span>
<span id="cb2-13"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> keepLive <span class="op">=</span> <span class="op">[&amp;]</span> <span class="op">&lt;</span><span class="kw">auto</span> r<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-14" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span> <span class="op">(!</span>std<span class="op">::</span>ranges<span class="op">::</span>any_of<span class="op">(</span></span>
<span id="cb2-15"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-15" aria-hidden="true" tabindex="-1"></a>        attributes_of<span class="op">(^</span>T<span class="op">)</span>,</span>
<span id="cb2-16"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">[</span>deprecatedAttribute<span class="op">]</span> <span class="op">(</span><span class="kw">auto</span> meta<span class="op">)</span> <span class="op">{</span> meta <span class="op">==</span> deprecatedAttributes; <span class="op">}</span></span>
<span id="cb2-17"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-17" aria-hidden="true" tabindex="-1"></a>      <span class="op">))</span> <span class="op">{</span></span>
<span id="cb2-18"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-18" aria-hidden="true" tabindex="-1"></a>        liveMembers<span class="op">.</span>push_back<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb2-19"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-19" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb2-20"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb2-21"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-22"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> member <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>members_of<span class="op">(^</span>User<span class="op">))</span> <span class="op">{</span></span>
<span id="cb2-23"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-23" aria-hidden="true" tabindex="-1"></a>      keepLive<span class="op">(</span>member<span class="op">)</span>;</span>
<span id="cb2-24"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-25"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> os;</span>
<span id="cb2-26"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-27"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-28"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-28" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Migrated user will no longer support deprecated fields</span></span>
<span id="cb2-29"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> MigratedUser;</span>
<span id="cb2-30"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-30" aria-hidden="true" tabindex="-1"></a>  define_class<span class="op">(^</span>MigratedUser, liveMembers<span class="op">(</span>currentUser<span class="op">))</span>;</span>
<span id="cb2-31"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb2-31" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h2 data-number="1.1" id="earlier-work"><span class="header-section-number">1.1</span> Earlier work<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#earlier-work" class="self-link"></a></h2>
<p>While collecting feedback on this draft, we were redirected to <span class="citation" data-cites="P1887R1">[<a href="https://wg21.link/p1887r1" role="doc-biblioref">P1887R1</a>]</span> as a pre existing proposal. In
this paper the author discusses two topics ‘user defined attributes’
(also in <span class="citation" data-cites="P2565R0">[<a href="https://wg21.link/p2565r0" role="doc-biblioref">P2565R0</a>]</span>) and reflection over said
attributes. We believe the two topics need not be conflated together,
both have intrinsic values on their own. We aim here to focus the
discussion entirely on <strong>standard</strong> attributes reflection.
Furthermore this earlier paper has not seen work following the
progression of <span class="citation" data-cites="P2996R4">[<a href="https://wg21.link/p2996r4" role="doc-biblioref">P2996R4</a>]</span> and so we feel this proposal is
in a good place to fill that gap.</p>
<h2 data-number="1.2" id="scope"><span class="header-section-number">1.2</span> Scope<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#scope" class="self-link"></a></h2>
<p>Attributes are split into standard and non standard. This proposal
wishes to limit itself to standard attributes (<span>9.12
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>). We feel
that since it is up to implementation to define how they handle non
standard attributes, it would lead to obscure situations that we don’t
claim to tackle here.<br>
A fairly (admittedly artificial) example can be built as such: Given an
implementation supporting a non standard <code class="sourceCode cpp"><span class="op">[[</span><span class="at">no_introspect</span><span class="op">]]</span></code>
attributes that suppress all reflection information appertaining to an
entity, we would have a hard time coming up with a self-consistent
system of rules to start with.<br>
</p>
<p>Henceforth in this proposal, both ‘attributes’ and ‘standard
attributes’ terms are meant to be equivalent.</p>
<h2 data-number="1.3" id="optionality-rule"><span class="header-section-number">1.3</span> Optionality rule<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#optionality-rule" class="self-link"></a></h2>
<p>There is a long standing and confusing discussion around the
ignorability of attributes. We’ll refer the reader to <span class="citation" data-cites="P2552R3">[<a href="https://wg21.link/p2552r3" role="doc-biblioref">P2552R3</a>]</span> for an at-length discussion of
this problem, and especially on what ‘ignorability’ really means. This
proposal agrees with the discussion carried there and in <span class="citation" data-cites="CWG2538">[<a href="https://wg21.link/cwg2538" role="doc-biblioref">CWG2538</a>]</span>. We also feel that whether an
implementation decides to semantically ignore a standard attribute
should not matter.<br>
</p>
<p>What matters more is self-consistency, when introspecting an
entity:</p>
<ul>
<li>We should be able to discover appertaining attributes</li>
<li>Declaring an entity with attributes discovered via introspection
yield the same result as what the implementation would offer if directly
declaring that entity with those attributes.</li>
</ul>
<h1 data-number="2" id="proposed-features"><span class="header-section-number">2</span> Proposed Features<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#proposed-features" class="self-link"></a></h1>
<p>We put ourselves in the context of <span class="citation" data-cites="P2996R4">[<a href="https://wg21.link/p2996r4" role="doc-biblioref">P2996R4</a>]</span> for this proposal to be more
illustrative in terms of what is being proposed.</p>
<h2 data-number="2.1" id="stdmetainfo"><span class="header-section-number">2.1</span> std::meta::info<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#stdmetainfo" class="self-link"></a></h2>
<p>We propose that attributes be a supported <em>reflectable</em>
property of the expression that are reflected upon. That means value of
type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
should be able to represent an attribute in addition to the currently
supported set.</p>
<h2 data-number="2.2" id="reflection-operator"><span class="header-section-number">2.2</span> Reflection operator<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#reflection-operator" class="self-link"></a></h2>
<p>The current proposition for reflection operator grammar does not
cover attributes, i.e.&nbsp;the expression <code class="sourceCode cpp"><span class="op">^[[</span><span class="at">deprecated</span><span class="op">]]</span></code>
is ill-formed. Our proposal advocates to support expression as
following</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb3-1" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> keepAttribute <span class="op">=</span> <span class="op">^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span></code></pre></div>
<p>The resulting value is a reflection value embedding relevant info for
the <em>attribute</em> entity, in this case the
<code class="sourceCode cpp">nodiscard</code> attribute.<br>
If the <em>attribute</em> is not a standard attribute, the expression is
ill-formed.</p>
<h2 data-number="2.3" id="splicers"><span class="header-section-number">2.3</span> Splicers<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#splicers" class="self-link"></a></h2>
<p>We propose that the syntax</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb4-1" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> r </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></span></code></pre></div>
<p>be supported in contexts where attributes are allowed.</p>
<ul>
<li><code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> r </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></code>
produces a potentially empty
<code class="sourceCode cpp"><em>attribute-list</em></code>
corresponding to the attributes reflected via reflection
<code class="sourceCode cpp">r</code>.</li>
</ul>
<p>Note that as it stands now
<code class="sourceCode cpp"><em>attribute-list</em></code>
(<span>9.12.1
<a href="https://wg21.link/dcl.attr.grammar">[dcl.attr.grammar]</a></span>)
does not cover
<code class="sourceCode cpp"><span class="kw">alignas</span></code>. We
understand that this limits potential use of the current proposal but
also comes with difficulty, so this will be discussed in a separate
paper.</p>
<p>An artifical example of splicer use using expansion statements is as
follows. We create an augmented
<code class="sourceCode cpp"><span class="kw">enum</span></code>
introducing a <code class="sourceCode cpp">begin</code> and
<code class="sourceCode cpp">last</code> enumerator while preserving the
original attributes</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span></span>
<span id="cb5-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> ErrorCode <span class="op">{</span></span>
<span id="cb5-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-4" aria-hidden="true" tabindex="-1"></a>      warn,</span>
<span id="cb5-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-5" aria-hidden="true" tabindex="-1"></a>      fatal,</span>
<span id="cb5-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb5-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> </span><span class="op">^</span><span class="at">ErrorCode </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></span>
<span id="cb5-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> ClosedErrorCode <span class="op">{</span></span>
<span id="cb5-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-10" aria-hidden="true" tabindex="-1"></a>      begin,</span>
<span id="cb5-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-11" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>enumerators_of<span class="op">(^</span>ErrorCode<span class="op">))</span> <span class="op">{</span></span>
<span id="cb5-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-12" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>,</span>
<span id="cb5-13"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb5-14"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-14" aria-hidden="true" tabindex="-1"></a>      last,</span>
<span id="cb5-15"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb5-16"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb5-16" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>If the attributes produced through introspection violate the rules of
what attributes can appertain to what entity, as usual the program is
ill-formed.</p>
<h3 data-number="2.3.1" id="attribute-using"><span class="header-section-number">2.3.1</span> Attribute using<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#attribute-using" class="self-link"></a></h3>
<p>It is worth pointing out the interaction between
<code class="sourceCode cpp"><em>attribute-using-prefix</em></code> and
splice expression that could lead to unexpected results.<br>
</p>
<p>In the following example</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb6-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> unscopedAttribute <span class="op">=</span> <span class="op">^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span>
<span id="cb6-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="kw">using</span><span class="at"> CC</span><span class="op">:</span><span class="at"> debug</span>,<span class="at"> </span><span class="op">[:</span><span class="at"> unscopedAttribute </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span> <span class="kw">enum</span> <span class="kw">class</span> Code <span class="op">{}</span>;</span>
<span id="cb6-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb6-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>While the user likely does not intend for the standard attributes to
be targeted by
<code class="sourceCode cpp"><span class="kw">using</span> CC</code>,
current grammar says that the prefix applies to attributes as they are
found in the subsequent list. To remediate this we can either enforce
that <code class="sourceCode cpp"><em>splice-name-qualifier</em></code>
precedes
<code class="sourceCode cpp"><em>attribute-using-prefix</em></code> or
have those constructs be mutually exclusive as they occur in <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></code>.<br>
To reduce the need to memorize unintuitive rules, we favor the later of
those options, as following</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb7-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> unscopedAttribute <span class="op">=</span> <span class="op">^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span>
<span id="cb7-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> unscopedAttribute </span><span class="op">:]</span><span class="at"> </span><span class="op">]][[</span><span class="at"> </span><span class="kw">using</span><span class="at"> CC</span><span class="op">:</span><span class="at"> debug </span><span class="op">]]</span> <span class="kw">enum</span> <span class="kw">class</span> Code <span class="op">{}</span>;</span>
<span id="cb7-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb7-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h2 data-number="2.4" id="metafunctions"><span class="header-section-number">2.4</span> Metafunctions<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#metafunctions" class="self-link"></a></h2>
<p>We propose to add two metafunctions to what is discussed already in
<span class="citation" data-cites="P2996R4">[<a href="https://wg21.link/p2996r4" role="doc-biblioref">P2996R4</a>]</span>. Additionally we will add
support for attributes in the other metafunctions where it makes
sense.</p>
<h3 data-number="2.4.1" id="attributes_of"><span class="header-section-number">2.4.1</span> attributes_of<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#attributes_of" class="self-link"></a></h3>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb8-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb8-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb8-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> attributes_of<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span>;</span>
<span id="cb8-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb8-5" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>This being applied to a reflection
<code class="sourceCode cpp">entity</code> will yield a sequence of
<code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
representing each individual attribute appertaining to
<code class="sourceCode cpp">entity</code>.</p>
<h3 data-number="2.4.2" id="is_attribute"><span class="header-section-number">2.4.2</span> is_attribute<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#is_attribute" class="self-link"></a></h3>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb9-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb9-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb9-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> is_attribute<span class="op">(</span>info entity<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb9-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb9-5" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>This would return true if the
<code class="sourceCode cpp">entity</code> reflection designates a <code class="sourceCode cpp"><span class="op">[</span> <span class="op">[</span> <em>attribute</em> <span class="op">]</span> <span class="op">]</span></code>,
otherwise it would return false.</p>
<h3 data-number="2.4.3" id="name_of-display_name_of"><span class="header-section-number">2.4.3</span> name_of, display_name_of<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#name_of-display_name_of" class="self-link"></a></h3>
<p>Given a reflection <code class="sourceCode cpp">r</code> designating
a standard attribute, <code class="sourceCode cpp">name_of<span class="op">(</span>r<span class="op">)</span></code>
(resp. <code class="sourceCode cpp">u8name_of<span class="op">(</span>r<span class="op">)</span></code>)
is encouraged to return a
<code class="sourceCode cpp">string_view</code> (resp.
<code class="sourceCode cpp">u8string_view</code>) corresponding to the
<code class="sourceCode cpp">attribute<span class="op">-</span>token</code>.
The same holds for the
<code class="sourceCode cpp">qualified_name_of</code> (resp.
<code class="sourceCode cpp">u8qualified_name_of</code>).<br>
</p>
<p>A toy example follows</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">nodiscard</span>,<span class="at"> deprecated</span><span class="op">(</span><span class="st">"Do not use me"</span><span class="op">)]]</span> <span class="dt">int</span> func<span class="op">()</span>;</span>
<span id="cb10-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> print_attributes<span class="op">(</span>std<span class="op">::</span>meta I<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-5" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="dt">bool</span> first<span class="op">{</span><span class="kw">true</span><span class="op">}</span>; <span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> std<span class="op">::</span>meta<span class="op">::</span>attributes_of<span class="op">(</span>I<span class="op">))</span> <span class="op">{</span></span>
<span id="cb10-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-6" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="op">(</span>std<span class="op">::</span>exchange<span class="op">(</span>first, <span class="kw">false</span><span class="op">)</span> <span class="op">?</span> <span class="st">""</span> <span class="op">:</span> <span class="st">", "</span><span class="op">)</span> </span>
<span id="cb10-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-7" aria-hidden="true" tabindex="-1"></a>                  <span class="op">&lt;&lt;</span> std<span class="op">::</span>meta<span class="op">::</span>name_of<span class="op">(</span>e<span class="op">)</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb10-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb10-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-11" aria-hidden="true" tabindex="-1"></a>    print_attributes<span class="op">(^</span>func<span class="op">)</span>; <span class="co">// Prints "nodiscard, deprecated"</span></span>
<span id="cb10-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb10-12" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Given a reflection <code class="sourceCode cpp">r</code> that
designates an individual attribute, <code class="sourceCode cpp">display_name_of<span class="op">(</span>r<span class="op">)</span></code>
(resp. <code class="sourceCode cpp">u8display_name_of<span class="op">(</span>r<span class="op">)</span></code>)
returns an unspecified non-empty
<code class="sourceCode cpp">string_view</code> (resp.
<code class="sourceCode cpp">u8string_view</code>). Implementations are
encouraged to produce text that is helpful in identifying the reflected
attribute.</p>
<h3 data-number="2.4.4" id="data_member_spec-define_class"><span class="header-section-number">2.4.4</span> data_member_spec,
define_class<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#data_member_spec-define_class" class="self-link"></a></h3>
<p>As it stands now <code class="sourceCode cpp">define_class</code>
allows piecewise building of a class via
<code class="sourceCode cpp">data_member_spec</code>. To support
attributes pertaining to those data members however, we’ll need to
augment <code class="sourceCode cpp">data_member_options_t</code> to
encode attributes we may want to attach to a data member.<br>
</p>
<p>The structure will change thusly</p>
<div>
<div class="sourceCode" id="cb11"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb11-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-2" aria-hidden="true" tabindex="-1"></a>    namespace std::meta {</span>
<span id="cb11-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-3" aria-hidden="true" tabindex="-1"></a>      struct data_member_options_t {</span>
<span id="cb11-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-4" aria-hidden="true" tabindex="-1"></a>        struct name_type {</span>
<span id="cb11-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-5" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires</span>
<span id="cb11-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-6" aria-hidden="true" tabindex="-1"></a>            constructible_from&lt;u8string, T&gt;</span>
<span id="cb11-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-7" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb11-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-9" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires</span>
<span id="cb11-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-10" aria-hidden="true" tabindex="-1"></a>            constructible_from&lt;string, T&gt;</span>
<span id="cb11-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-11" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb11-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-12" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb11-13"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-14"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-14" aria-hidden="true" tabindex="-1"></a>        optional&lt;name_type&gt; name;</span>
<span id="cb11-15"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-15" aria-hidden="true" tabindex="-1"></a>        bool is_static = false;</span>
<span id="cb11-16"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-16" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; alignment;</span>
<span id="cb11-17"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-17" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; width;</span>
<span id="cb11-18"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-18" aria-hidden="true" tabindex="-1"></a><span class="va">+       vector&lt;info&gt;  attributes;</span></span>
<span id="cb11-19"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-19" aria-hidden="true" tabindex="-1"></a>      };</span>
<span id="cb11-20"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-20" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb11-21"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb11-21" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
</div>
<p>From there building a class piecewise proceeds as usual</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Empty <span class="op">{}</span>;</span>
<span id="cb12-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> S;</span>
<span id="cb12-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-4" aria-hidden="true" tabindex="-1"></a>    define_class<span class="op">(^</span>S, <span class="op">{</span></span>
<span id="cb12-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-5" aria-hidden="true" tabindex="-1"></a>      data_member_spec<span class="op">(^</span><span class="dt">int</span>, <span class="op">{.</span>name <span class="op">=</span> <span class="st">"i"</span><span class="op">})</span>,</span>
<span id="cb12-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-6" aria-hidden="true" tabindex="-1"></a>      data_member_spec<span class="op">(^</span>Empty, <span class="op">{.</span>name <span class="op">=</span> <span class="st">"e"</span>, </span>
<span id="cb12-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-7" aria-hidden="true" tabindex="-1"></a>                                <span class="op">.</span>attributes <span class="op">=</span> <span class="op">{^[[</span><span class="at">no_unique_address</span><span class="op">]]}})</span></span>
<span id="cb12-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb12-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-10"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Equivalent to</span></span>
<span id="cb12-11"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// struct [<a href="http://eel.is/c++draft/nodiscard" class="wg21_link">[nodiscard]</a>] S {</span></span>
<span id="cb12-12"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   int i;</span></span>
<span id="cb12-13"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   [[no_unique_address]] Empty e;</span></span>
<span id="cb12-14"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// };</span></span>
<span id="cb12-15"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb12-15" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h3 data-number="2.4.5" id="other-metafunctions"><span class="header-section-number">2.4.5</span> Other metafunctions<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#other-metafunctions" class="self-link"></a></h3>
<p>For any reflection where
<code class="sourceCode cpp">is_attribute</code> returns false, other
metafunctions not listed above are not considered constant
expressions</p>
<h2 data-number="2.5" id="queries"><span class="header-section-number">2.5</span> Queries<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#queries" class="self-link"></a></h2>
<p>We do not think it is necessary to introduce additional query or
queries at this point. Especially we would not recommend to introduce a
dedicated query per attribute (eg
<code class="sourceCode cpp">is_deprecated</code>,
<code class="sourceCode cpp">is_nouniqueaddress</code>, etc.). Having
said that, we feel those should be acheivable via concepts, something
akin to</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-2"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> deprecatedAttributes <span class="op">=</span> std<span class="op">::</span>meta<span class="op">::</span>attributes_of<span class="op">(^[[</span><span class="at">deprecated</span><span class="op">]])</span>;</span>
<span id="cb13-3"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-4" 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="cb13-5"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> IsDeprecated <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>any_of<span class="op">(</span></span>
<span id="cb13-6"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-6" aria-hidden="true" tabindex="-1"></a>      attributes_of<span class="op">(^</span>T<span class="op">)</span>,</span>
<span id="cb13-7"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">[</span>deprecatedAttributes<span class="op">]</span> <span class="op">(</span><span class="kw">auto</span> meta<span class="op">)</span> <span class="op">{</span> meta <span class="op">==</span> deprecatedAttributes<span class="op">[</span><span class="dv">0</span><span class="op">]</span>; <span class="op">}</span></span>
<span id="cb13-8"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span>;</span>
<span id="cb13-9"><a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#cb13-9" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h1 data-number="3" id="proposed-wording"><span class="header-section-number">3</span> Proposed wording<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#proposed-wording" class="self-link"></a></h1>
<h2 data-number="3.1" id="language"><span class="header-section-number">3.1</span> Language<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#language" class="self-link"></a></h2>
<h3 data-number="3.1.1" id="dcl.attr.grammar-attribute-syntax-and-semantics"><span class="header-section-number">3.1.1</span> <a href="http://eel.is/c++draft/dcl.attr.grammar" class="wg21_link">[dcl.attr.grammar]</a> Attribute
syntax and semantics<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#dcl.attr.grammar-attribute-syntax-and-semantics" class="self-link"></a></h3>
<p>Change the grammar to allow splicing attributes from reflection in
<span>9.12.1
<a href="https://wg21.link/dcl.attr.grammar">[dcl.attr.grammar]</a></span>
as follows</p>
<blockquote>
<div class="line-block"><em>attribute-specifier:</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ [ <em>attribute-using-prefix<sub>opt</sub></em>
<em>attribute-list</em> ] ]</div>
<div class="add" style="color: #006e28">

<div class="line-block">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ [ <em>splice-name-qualifier</em> ]
]</div>

</div>
</blockquote>
<p>Following this subsection modify the paragraph 7</p>
<div class="diff">
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
Two consecutive left square bracket tokens shall appear only when
introducing an
<code class="sourceCode cpp"><em>attribute-specifier</em></code> <span class="rm" style="color: #bf0303"><del>or</del></span><span class="add" style="color: #006e28"><ins>,</ins></span> within the
<code class="sourceCode cpp"><em>balanced-token-seq</em></code> of an
<code class="sourceCode cpp"><em>attribute-argument-clause</em></code>
<span class="add" style="color: #006e28"><ins>or as part of a
<span><code class="sourceCode default"><em>reflect-expression</em></code></span></ins></span>.</p>
</div>
<p>Add the following paragraph</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
If an
<code class="sourceCode default"><em>attribute-specifier</em></code>
contains a
<code class="sourceCode default">splice-name-qualifier</code>, every
standard attribute described by that reflection must be applied to the
entity that
<code class="sourceCode default"><em>attribute-specifier</em></code> is
attached to. The form of this expansion shall be treated as an
<code class="sourceCode default">attribute-list</code>. If
<code class="sourceCode default"><em>splice-name-qualifier</em></code>
describes an entity for which no attributes were specified, it has no
effect.</p>
</div>
<h3 data-number="3.1.2" id="expr.unary.general-general"><span class="header-section-number">3.1.2</span> <a href="http://eel.is/c++draft/expr.unary.general" class="wg21_link">[expr.unary.general]</a>
General<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#expr.unary.general-general" class="self-link"></a></h3>
<p>Augment the
<code class="sourceCode cpp"><span class="op">^</span></code> operator
to allow for reflection on attribute in <span>7.6.2.1
<a href="https://wg21.link/expr.unary.general">[expr.unary.general]</a></span>
as follows</p>
<blockquote>
<div class="line-block"><em>reflect-expression:</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<code class="sourceCode cpp"><span class="op">::</span></code><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<em>namespace-name</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<em>nested-name-specifier<sub>opt</sub></em>
<em>template-name</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<em>nested-name-specifier<sub>opt</sub></em> <em>concept-name</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<em>type-id</em><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode cpp"><span class="op">^</span></code>
<em>id-expression</em></div>
<div class="add" style="color: #006e28">

<div class="line-block">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code class="sourceCode default">^ [ [</code>
<em>attribute</em> <code class="sourceCode default">] ]</code></div>

</div>
</blockquote>
<h3 data-number="3.1.3" id="expr.reflect-the-reflection-operator"><span class="header-section-number">3.1.3</span> <a href="http://eel.is/c++draft/expr.reflect" class="wg21_link">[expr.reflect]</a> The reflection
operator<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#expr.reflect-the-reflection-operator" class="self-link"></a></h3>
<p>Modify the subsection <a href="http://eel.is/c++draft/expr.reflect" class="wg21_link">[expr.reflect]</a> to describe reflection applying
to attributes, adding the following paragraph</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">11</a></span> When
applied to a <code class="sourceCode default">[ [</code>
<em>attribute</em> <code class="sourceCode default">] ]</code>, the
reflection operator produces a reflection for the indicated
<em>attribute</em>. If <em>attribute</em> is not described in <span>9.12
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>, the behavior
is implementation defined.</p>
</div>
<h2 data-number="3.2" id="library"><span class="header-section-number">3.2</span> Library<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#library" class="self-link"></a></h2>
<h3 data-number="3.2.1" id="meta.synop-header-meta-synopsis"><span class="header-section-number">3.2.1</span> <a href="http://eel.is/c++draft/meta.synop" class="wg21_link">[meta.synop]</a> Header
<code class="sourceCode cpp"><span class="op">&lt;</span></code>meta<code class="sourceCode cpp"><span class="op">&gt;</span></code>
synopsis<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#meta.synop-header-meta-synopsis" class="self-link"></a></h3>
<p>Add to the <a href="http://eel.is/c++draft/meta.reflection.queries" class="wg21_link">[meta.reflection.queries]</a> section from the synopsis the
two metafunctions as follow</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="line-block"><code class="sourceCode default">consteval bool is_attribute(info r);</code><br>
<code class="sourceCode default">consteval vector&lt;info&gt; attributes_of(info r);</code></div>
</blockquote>

</div>
<h3 data-number="3.2.2" id="meta.reflection.queries-reflection-queries"><span class="header-section-number">3.2.2</span> <a href="http://eel.is/c++draft/meta.reflection.queries" class="wg21_link">[meta.reflection.queries]</a>,
Reflection queries<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#meta.reflection.queries-reflection-queries" class="self-link"></a></h3>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">42</a></span> <code class="sourceCode default">consteval bool is_attribute(info r);</code></p>
<p>Returns: <code class="sourceCode default">true</code> if r designates
a standard attribute. Otherwise,
<code class="sourceCode default">false</code>.</p>
<p><code class="sourceCode default">consteval vector&lt;info&gt; attributes_of(info r);</code></p>
<p>Returns: A vector containing a reflection for each of the attributes
that appertain to the entity r</p>
</div>
<h1 data-number="4" id="discussion"><span class="header-section-number">4</span> Discussion<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#discussion" class="self-link"></a></h1>
<p>Originally the idea of introducing a <code class="sourceCode cpp">declattr<span class="op">(</span>Expression<span class="op">)</span></code>
keyword seemed the most straightforward to tackle this problem, but from
feedback the concern of introspecting on expression attributes was a
concern that belongs with the reflection SG. The current proposal
shifted away from the original
<code class="sourceCode cpp">declattr</code> idea to align better with
the reflection toolbox. Note also that as we advocate here for <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> r </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></code>
to be supported, we recover the ease of use that we first envisioned
<code class="sourceCode cpp">declattr</code> to have.</p>
<h1 data-number="5" id="bibliography"><span class="header-section-number">5</span> References<a href="https://devhtml.dev.bloomberg.com/~acassagnes/proposal.html#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-CWG2538" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/Cwg2538" class="wg21_link">CWG2538</a>] Jens Maurer. 2021-12-02. Can standard attributes be
syntactically ignored? <a href="https://wg21.link/cwg2538"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/cwg2538" class="wg21_link">cwg2538</a></div></a>
</div>
<div id="ref-P1887R1" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/P1887R1" class="wg21_link">P1887R1</a>] Corentin Jabot. 2020-01-13. Reflection on attributes. <a href="https://wg21.link/p1887r1"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/p1887r1" class="wg21_link">p1887r1</a></div></a>
</div>
<div id="ref-P2237R0" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/P2237R0" class="wg21_link">P2237R0</a>] Andrew Sutton. 2020-10-15. Metaprogramming. <a href="https://wg21.link/p2237r0"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/p2237r0" class="wg21_link">p2237r0</a></div></a>
</div>
<div id="ref-P2552R3" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/P2552R3" class="wg21_link">P2552R3</a>] Timur Doumler. 2023-06-14. On the ignorability of standard
attributes. <a href="https://wg21.link/p2552r3"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/p2552r3" class="wg21_link">p2552r3</a></div></a>
</div>
<div id="ref-P2565R0" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/P2565R0" class="wg21_link">P2565R0</a>] Bret Brown. 2022-03-16. Supporting User-Defined Attributes. <a href="https://wg21.link/p2565r0"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/p2565r0" class="wg21_link">p2565r0</a></div></a>
</div>
<div id="ref-P2996R4" class="csl-entry" role="doc-biblioentry">
[<a href="https://wg21.link/P2996R4" class="wg21_link">P2996R4</a>] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-06-26. Reflection for
C++26. <a href="https://wg21.link/p2996r4"><div class="csl-block">https://wg21.link/<a href="https://wg21.link/p2996r4" class="wg21_link">p2996r4</a></div></a>
</div>
</div>
</div>
</div>



</body></html>