<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<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="2025-05-18" />
  <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]-->
</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">
  <tr>
    <td>Document #:</td>
    <td>
      P3385R5
      [<a href="https://wg21.link/P3385">Latest</a>]
      [<a href="https://wg21.link/P3385/status">Status</a>]
    </td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-05-18</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG, LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Aurelien Cassagnes<br>&lt;<a href="mailto:acassagnes@bloomberg.net" class="email">acassagnes@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">1</span> Revision
history<span></span></a></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#earlier-work" id="toc-earlier-work"><span class="toc-section-number">2.1</span> Earlier work<span></span></a></li>
<li><a href="#scope" id="toc-scope"><span class="toc-section-number">2.2</span> Scope<span></span></a></li>
<li><a href="#self-consistency-and-optionality-rule" id="toc-self-consistency-and-optionality-rule"><span class="toc-section-number">2.3</span> Self consistency and optionality
rule<span></span></a></li>
</ul></li>
<li><a href="#proposed-features" id="toc-proposed-features"><span class="toc-section-number">3</span> Proposed Features<span></span></a>
<ul>
<li><a href="#info" id="toc-info"><span class="toc-section-number">3.1</span> info<span></span></a></li>
<li><a href="#reflection-operator" id="toc-reflection-operator"><span class="toc-section-number">3.2</span> Reflection
operator<span></span></a></li>
<li><a href="#splicers" id="toc-splicers"><span class="toc-section-number">3.3</span> Splicers<span></span></a></li>
<li><a href="#metafunctions" id="toc-metafunctions"><span class="toc-section-number">3.4</span>
Metafunctions<span></span></a></li>
<li><a href="#queries" id="toc-queries"><span class="toc-section-number">3.5</span> Queries<span></span></a></li>
</ul></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">4</span> Proposed wording<span></span></a>
<ul>
<li><a href="#language" id="toc-language"><span class="toc-section-number">4.1</span> Language<span></span></a></li>
<li><a href="#library" id="toc-library"><span class="toc-section-number">4.2</span> Library<span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">4.3</span> Feature-test
macro<span></span></a></li>
</ul></li>
<li><a href="#feedback" id="toc-feedback"><span class="toc-section-number">5</span> Feedback<span></span></a>
<ul>
<li><a href="#poll" id="toc-poll"><span class="toc-section-number">5.1</span> Poll<span></span></a></li>
<li><a href="#implementation" id="toc-implementation"><span class="toc-section-number">5.2</span>
Implementation<span></span></a></li>
</ul></li>
<li><a href="#conclusion" id="toc-conclusion"><span class="toc-section-number">6</span> Conclusion<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="revision-history"><span class="header-section-number">1</span> Revision history<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P3385R4"><a href="https://wg21.link/p3385r4" role="doc-biblioref">[P3385R4]</a></span></p>
<ul>
<li>Remove in-place splicer syntax</li>
<li>Add <code class="sourceCode cpp">appertain</code> metafunction</li>
<li>Augment implementation feedback</li>
</ul>
<h1 data-number="2" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Attributes are used to a great extent, and there is new attributes
being added to the language somewhat regularly.<br />
As reflection makes its way into our standard, we are missing a way for
generic code to look into the attributes appertaining to an entity. That
is what this proposal aims to tackle by introducing the building
blocks.<br />
We expect a 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, for example, 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. The following example demonstrates skipping over deprecated
members:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> User <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-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="cb1-4"><a href="#cb1-4" 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="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string uuidv5;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string countryIsoCode;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> std<span class="op">::</span>meta<span class="op">::</span>info filterOutDeprecated<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>info<span class="op">&gt;</span> liveMembers;</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> attributes <span class="op">=</span> attributes_of<span class="op">(^^[[</span><span class="at">deprecated</span><span class="op">]])</span>;</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> keepLive <span class="op">=</span> <span class="op">[&amp;]</span> <span class="op">(</span>info r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-13"><a href="#cb1-13" 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="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>        attributes_of<span class="op">(^^</span>r<span class="op">)</span>,</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">[&amp;]</span> <span class="op">(</span><span class="kw">auto</span> meta<span class="op">)</span> <span class="op">{</span> meta <span class="op">==</span> attributes<span class="op">[</span><span class="dv">0</span><span class="op">]</span>; <span class="op">}</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>      <span class="op">))</span> <span class="op">{</span></span>
<span id="cb1-17"><a href="#cb1-17" 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="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Migrated user will no longer support deprecated fields</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> MigratedUser;</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="op">{</span> define_aggregate<span class="op">(^^</span>MigratedUser, selectNonDeprecated<span class="op">())</span>; <span class="op">}</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-25"><a href="#cb1-25" 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> member <span class="op">:</span> members_of<span class="op">(^^</span>User<span class="op">))</span> <span class="op">{</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a>      keepLive<span class="op">(</span>member<span class="op">)</span>;</span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">^^</span>MigratedUser;</span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a>  </span></code></pre></div>
<h2 data-number="2.1" id="earlier-work"><span class="header-section-number">2.1</span> Earlier work<a href="#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>, 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 these two topics need not be conflated; both have
intrinsic values on their own. We aim to focus this discussion entirely
on <strong>standard</strong> attributes reflection. Furthermore the
earlier paper has not seen work following the progression of <span class="citation" data-cites="P2996R11"><a href="https://wg21.link/p2996r11" role="doc-biblioref">[P2996R11]</a></span>, and so we feel this proposal
is in a good place to fill that gap.</p>
<h2 data-number="2.2" id="scope"><span class="header-section-number">2.2</span> Scope<a href="#scope" class="self-link"></a></h2>
<h3 data-number="2.2.1" id="standard-vs-arbitrary-attributes"><span class="header-section-number">2.2.1</span> Standard vs arbitrary
attributes<a href="#standard-vs-arbitrary-attributes" class="self-link"></a></h3>
<p>Attributes are colloquially split into standard and non-standard. The
current wording in the standard states that attributes which are not
recognized are ignored, without being clear on what <em>ignoring</em>
means here. When we speak about reflection and attributes, what matter
is whether they are kept alive until semantic analysis. While this is
true for standard attributes, regardless of whether recommendations from
the standard are applied (eg. Warning on ignoring a
<code class="sourceCode cpp">nodiscard</code> marked entity), it is less
clear whether that holds as well for non-standard ones. The proposal
does not ask for implementation to change their current scheme, how “non
standard attributes”, “reflection” and “ignorability” interact together
will be discussed further in following <a href="#optionality-rule">paragraph</a>.</p>
<p>To summarize, this proposal (via wording) wishes to be prescriptive
when it comes to standard attributes (<span>9.13
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>) and
permissive when it comes to non-standard.</p>
<h3 data-number="2.2.2" id="argument-clause"><span class="header-section-number">2.2.2</span> Argument clause<a href="#argument-clause" class="self-link"></a></h3>
<p>Revisions of this proposal up to <span class="citation" data-cites="P3385R2"><a href="https://wg21.link/p3385r2" role="doc-biblioref">[P3385R2]</a></span> were willfully ignoring
<em>attribute-argument-clause</em>, prescriptively so when it comes to
comparison (ie. <code class="sourceCode cpp"><span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">(</span><span class="st">&quot;foo&quot;</span><span class="op">)]]</span> <span class="op">==</span> <span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">(</span><span class="st">&quot;bar&quot;</span><span class="op">)]]</span></code>).
Feedback post Wroclaw was unanimous on the need to support argument
clause. Feedback from implementers on this feature has been that while
it brings no concern for attributes like
<code class="sourceCode cpp">nodiscard</code>, it was unrealistic in the
case of <code class="sourceCode cpp">assume</code> that accepts an
arbitrary expression as argument.<br />
</p>
<p>Note that this is at this point a somewhat artificial concern as
there is no meaningful way to reflect on a null statement, which is what
<code class="sourceCode cpp">assume</code> appertains to. The only way
to get a reflection of assume would be to explicitly construct one via
<code class="sourceCode cpp"><span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> <span class="op">^^[[</span><span class="at">assume</span><span class="op">(</span><span class="at"><em>expr</em></span><span class="op">)]]</span>;</code>
<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>. For any other entity, there is no
call to <code class="sourceCode cpp">attributes_of</code> that could
return a reflection of <code class="sourceCode cpp">assume</code>
attribute.</p>
<p>Let us recap here what are the attributes <span>9.13
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span> found in the
standard and their argument clause</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Attribute</strong>
</div></th>
<th><div style="text-align:center">
<strong>Argument-clause</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>assume</td>
<td>conditional-expression</td>
</tr>
<tr class="even">
<td>carries_dependency</td>
<td>N/A</td>
</tr>
<tr class="odd">
<td>deprecated</td>
<td>unevaluated-string</td>
</tr>
<tr class="even">
<td>fallthrough</td>
<td>N/A</td>
</tr>
<tr class="odd">
<td>indeterminate</td>
<td>N/A</td>
</tr>
<tr class="even">
<td>likely</td>
<td>N/A</td>
</tr>
<tr class="odd">
<td>maybe_unused</td>
<td>N/A</td>
</tr>
<tr class="even">
<td>nodiscard</td>
<td>unevaluated-string</td>
</tr>
<tr class="odd">
<td>noreturn</td>
<td>N/A</td>
</tr>
<tr class="even">
<td>no_unique_address</td>
<td>N/A</td>
</tr>
<tr class="odd">
<td>unlikely</td>
<td>N/A</td>
</tr>
</tbody>
</table>
<p>Besides the <code class="sourceCode cpp">assume</code> case, the
arguments are unproblematic.<br />
On the other hand if we look at implementation specific attributes,
we’ll see that arguments can take arbitrary shape; without listing (<a href="https://clang.llvm.org/docs/AttributeReference.html">all</a>)
clang recognized attributes, we’ll share one example here</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="op">[[</span><span class="ex">clang::availability</span><span class="op">(</span><span class="at">macos</span>,<span class="at">introduced</span><span class="op">=</span><span class="dv">10</span><span class="er">.4</span>,<span class="at">deprecated</span><span class="op">=</span><span class="dv">10</span><span class="er">.6</span>,<span class="at">obsoleted</span><span class="op">=</span><span class="dv">10</span><span class="er">.7</span><span class="op">)]]</span> <span class="dt">void</span> f<span class="op">()</span>;</span></code></pre></div>
<p>There is no standard way to express the shape of the arguments
(<em>list of tag = value where tags are from a predetermined set ?</em>)
to be supported here, short of treating those arguments clause as
unevaluated soup of arbitrary tokens… Arguably when the generative side
of reflection does pick up momentum, this will be revisited.</p>
<p>In the end, the current proposal aims to cover the most realistic use
cases today by rendering ill formed the reflection of attributes with
<em>conditional-expression</em> argument clause, leaving it open for
future standard to lift that restriction.</p>
<h2 data-number="2.3" id="self-consistency-and-optionality-rule"><span class="header-section-number">2.3</span> Self consistency and
optionality rule<a href="#self-consistency-and-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 with regard to what ‘ignorability’ really
means. Another interesting conversation takes place in <span class="citation" data-cites="P3254R0"><a href="https://wg21.link/p3254r0" role="doc-biblioref">[P3254R0]</a></span>, around the <code class="sourceCode cpp"><span class="op">[[</span><span class="at">no_unique_address</span><span class="op">]]</span></code>
case, which serves again to illustrate that the tension around so called
ignorability should not be considered a novel feature of this
proposal.</p>
<p>We claim that whether an implementation decides to semantically
ignore a standard attribute (by not applying the <em>recommended
practices</em>) does not matter in the context of this proposal. What
does matter is that attributes and reflection interact in a
self-consistent fashion. To that aim we think the following guidelines
provide a decent sandbox</p>
<ol type="1">
<li>Reflecting on an ignored attribute shall be undistinguishable from
reflecting on <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></code>.</li>
<li>Splicing attributes on a declaration shall be undistinguishable from
manually appertaining those attributes to this declaration.</li>
</ol>
<p><u>About the first rule</u><br />
For <em>standard attribute</em>, the first rule does not come into the
picture as they are not syntactically ignorable.<br />
For <em>implementation specific attributes</em> <a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>, if
a particular implementation wishes to ignore this attribute then the
first rule says the implementation should treat this as an empty
attribute list.</p>
<p><u>About the second rule</u><br />
For <em>standard attribute</em>, this rule simply enforce appertainance
rule as they are usually prescribed in the standard.<br />
For <em>implementation specific attributes</em>, this rule means that if
an implementation choses to ignore a particular attribute, splicing a
reflection of that attribute will trigger the same ignorability
trap.</p>
<h1 data-number="3" id="proposed-features"><span class="header-section-number">3</span> Proposed Features<a href="#proposed-features" class="self-link"></a></h1>
<p>We put ourselves in the context of <span class="citation" data-cites="P2996R11"><a href="https://wg21.link/p2996r11" role="doc-biblioref">[P2996R11]</a></span> for this proposal to be more
illustrative in terms of what is being proposed.</p>
<h2 data-number="3.1" id="info"><span class="header-section-number">3.1</span> info<a href="#info" class="self-link"></a></h2>
<p>We propose that attributes be a supported <em>reflectable</em>
property of the expression that is 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="3.2" id="reflection-operator"><span class="header-section-number">3.2</span> Reflection operator<a href="#reflection-operator" class="self-link"></a></h2>
<p>The current proposition for reflection operator grammar does not
cover attributes, i.e., 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="#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 salient property
of the attribute which are the token and the attribute argument clause
if any. If the <em>attribute</em> is not a standard attribute, as per
our earlier discussion, an implementation is free to either compute that
reflection or to treat this as a reflection over a vanishing
attribute.</p>
<h2 data-number="3.3" id="splicers"><span class="header-section-number">3.3</span> Splicers<a href="#splicers" class="self-link"></a></h2>
<p>There is <strong>no</strong> support for splicing attributes in
place. Up to and including <span class="citation" data-cites="P3385R4"><a href="https://wg21.link/p3385r4" role="doc-biblioref">[P3385R4]</a></span> we were offering that a splice
syntax be supported to splice attributes at declaration location</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="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>A simple example of splicer is as follows where 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">end</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="#cb5-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> ErrorCode <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>      warn,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>      fatal,</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    </span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> <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> ClosedErrorCode <span class="op">{</span> <span class="co">// identical to `enum class [[nodiscard]] ClosedErrorCode {`</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>      begin,</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>      <span class="co">// ...</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>      end,</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Since we feel the lookup inside <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></code>
needs to be designed more carefully than what we were offering in our
proposal, we are removing support for <em>in-place</em> splicing
attributes in place, in favor of an
<code class="sourceCode cpp">appertain<span class="op">()</span></code>
metafunction. We will in the future review carefully how that feature
should be designed if at all.</p>
<h2 data-number="3.4" id="metafunctions"><span class="header-section-number">3.4</span> Metafunctions<a href="#metafunctions" class="self-link"></a></h2>
<p>We propose to add couple of metafunctions to what has already been
discussed in <span class="citation" data-cites="P2996R11"><a href="https://wg21.link/p2996r11" role="doc-biblioref">[P2996R11]</a></span>. In addition, we will extend
support to attributes in the other metafunctions, when it makes
sense.</p>
<h3 data-number="3.4.1" id="attributes_of"><span class="header-section-number">3.4.1</span> attributes_of<a href="#attributes_of" class="self-link"></a></h3>
<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>
<span id="cb6-2"><a href="#cb6-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="cb6-3"><a href="#cb6-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="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>This would return a vector of reflections representing individual
attributes that were appertaining to reflected upon entity.</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>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> ErrorCode <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>      Disconnected,</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>      ConfigurationIncorrect,</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>      OutdatedCredentials,</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>attributes_of<span class="op">(^^</span>ErrorCode<span class="op">)[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">]])</span>;</span></code></pre></div>
<h3 data-number="3.4.2" id="is_attribute"><span class="header-section-number">3.4.2</span> is_attribute<a href="#is_attribute" class="self-link"></a></h3>
<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>
<span id="cb8-2"><a href="#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="#cb8-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="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb8-5"><a href="#cb8-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 represents 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>
such as described in [dcl.attr], otherwise, it would return false. For
vendor specific attributes, behavior is left to implementation.</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>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>is_attribute<span class="op">(^^[[</span><span class="at">nodiscard</span><span class="op">]]))</span>;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>is_attribute<span class="op">(^^[[</span><span class="ex">clang::disable_tail_calls</span><span class="op">]]))</span>; <span class="co">// Implementation defined</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h3 data-number="3.4.3" id="appertain"><span class="header-section-number">3.4.3</span> appertain<a href="#appertain" class="self-link"></a></h3>
<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>
<span id="cb10-2"><a href="#cb10-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="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="op">&lt;</span>reflection_range R <span class="op">=</span> initializer_list<span class="op">&lt;</span>info<span class="op">&gt;&gt;</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>      <span class="kw">consteval</span> <span class="kw">auto</span> appertain<span class="op">(</span>info entity, R<span class="op">&amp;&amp;</span> attributes<span class="op">)</span> <span class="op">-&gt;</span> info;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>This would appertain to <code class="sourceCode cpp">entity</code>
each attribute reflection in
<code class="sourceCode cpp">attributes</code>.</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>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Foo;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>      define_aggregate<span class="op">(^^</span>Foo, <span class="op">{})</span>;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> r <span class="op">=</span> appertain<span class="op">(^^</span>Foo, <span class="op">{</span> <span class="op">^^[[</span><span class="at">maybe_unused</span><span class="op">]]</span> <span class="op">})</span>;</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>attributes_of<span class="op">(^^</span>r<span class="op">)[</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="op">^^[[</span><span class="at">maybe_unused</span><span class="op">]])</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h3 data-number="3.4.4" id="identifier_of-display_string_of"><span class="header-section-number">3.4.4</span> identifier_of,
display_string_of<a href="#identifier_of-display_string_of" class="self-link"></a></h3>
<p>Given a reflection <code class="sourceCode cpp">r</code> designating
a standard attribute, <code class="sourceCode cpp">identifier_of<span class="op">(</span>r<span class="op">)</span></code>
(resp. <code class="sourceCode cpp">u8identifier_of<span class="op">(</span>r<span class="op">)</span></code>)
should 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>.
We do not think the leading
<code class="sourceCode cpp"><span class="op">[[</span></code> and
closing <code class="sourceCode cpp"><span class="op">]]</span></code>
are meaningful, besides, they contribute visual noise.</p>
<p>A sample follows</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></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> <span class="dt">int</span> func<span class="op">()</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> nodiscard <span class="op">=</span> attributes_of<span class="op">(^^</span>func<span class="op">)</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>identifier_of<span class="op">(</span>nodiscard<span class="op">[</span><span class="dv">0</span><span class="op">])</span> <span class="op">==</span> identifier_of<span class="op">(^^[[</span><span class="at">nodiscard</span><span class="op">]]))</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>identifier_of<span class="op">(</span>nodiscard<span class="op">[</span><span class="dv">0</span><span class="op">])</span> <span class="op">==</span> <span class="st">&quot;nodiscard&quot;</span><span class="op">)</span>; <span class="co">// != &quot;[[nodiscard]]&quot;</span></span>
<span id="cb12-6"><a href="#cb12-6" 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_string_of<span class="op">(</span>r<span class="op">)</span></code>
(resp. <code class="sourceCode cpp">u8display_string_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 for display purpose. In the preceding example we could imagine
printing <code class="sourceCode cpp"><span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span></code>
instead of <code class="sourceCode cpp">nodiscard</code> as it might be
better fitted for log extraction.</p>
<h3 data-number="3.4.5" id="data_member_spec-define_aggregate"><span class="header-section-number">3.4.5</span> data_member_spec,
define_aggregate<a href="#data_member_spec-define_aggregate" class="self-link"></a></h3>
<p>As it stands now,
<code class="sourceCode cpp">define_aggregate</code> allows piecewise
building of a class via
<code class="sourceCode cpp">data_member_spec</code>. However, to
support arbitrary attributes pertaining to those data members, we’ll
need to augment <code class="sourceCode cpp">data_member_options</code>
to encode attributes we may want to attach to a data member.<br />
</p>
<p>The structure would change thusly:</p>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    namespace std::meta {</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>      struct data_member_options {</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>        struct name_type {</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;u8string, T&gt;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;string, T&gt;</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>        optional&lt;name_type&gt; name;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; alignment;</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; bit_width;</span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a><span class="va">+       vector&lt;info&gt; attributes;</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a><span class="st">-       bool no_unique_address = false;</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a><span class="va">+       [[deprecated]] bool no_unique_address = false;</span></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>      };</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
</div>
<p>From there building an aggregate piecewise proceeds as usual</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></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Empty <span class="op">{}</span>;</span>
<span id="cb14-3"><a href="#cb14-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="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">consteval</span> <span class="op">{</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>      define_aggregate<span class="op">(^^</span>S, <span class="op">{</span></span>
<span id="cb14-6"><a href="#cb14-6" 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">&quot;i&quot;</span><span class="op">})</span>,</span>
<span id="cb14-7"><a href="#cb14-7" 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">&quot;e&quot;</span>, </span>
<span id="cb14-8"><a href="#cb14-8" 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="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>      <span class="op">})</span>;</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Equivalent to</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">// struct [[nodiscard]] S {</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   int i;</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   [[no_unique_address]] struct Empty { } e;</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>    <span class="co">// };</span></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Note here that <span class="citation" data-cites="P2996R11"><a href="https://wg21.link/p2996r11" role="doc-biblioref">[P2996R11]</a></span> includes
<code class="sourceCode cpp">no_unique_address</code> and
<code class="sourceCode cpp">alignment</code> as part of
<code class="sourceCode cpp">data_member_options</code> API. We think
that this approach scale awkwardly in that every new attributes
introduced into the standard will lead to discussions on whether or not
they should be included in
<code class="sourceCode cpp">data_member_options</code>. Attaching
attributes through the above proposed approach is more in line with the
philosophy of leveraging <code class="sourceCode cpp">info</code> as the
opaque vehicle to carry every and all reflections.</p>
<p>We will not pursue this change here in this proposal but in a
follow-up paper <span class="citation" data-cites="P3678R0"><a href="#ref-P3678R0" role="doc-biblioref"><strong>P3678R0?</strong></a></span>, as we wish to
keep the scope of change here rather small.</p>
<h3 data-number="3.4.6" id="other-metafunctions"><span class="header-section-number">3.4.6</span> Other metafunctions<a href="#other-metafunctions" class="self-link"></a></h3>
<p>For any reflection where
<code class="sourceCode cpp">is_attribute</code> returns
<code class="sourceCode cpp"><span class="kw">true</span></code>, other
metafunctions not listed above are not considered constant
expressions</p>
<h2 data-number="3.5" id="queries"><span class="header-section-number">3.5</span> Queries<a href="#queries" class="self-link"></a></h2>
<p>We do not think it is necessary to introduce any additional query or
queries at this point. We would especially not recommend introducing a
dedicated query per attribute (e.g.,
<code class="sourceCode cpp">is_deprecated</code>,
<code class="sourceCode cpp">is_nouniqueaddress</code>, etc.). Having
said that, we feel those should be achievable via concepts, something
akin to:</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></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> deprecated <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="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-4"><a href="#cb15-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="cb15-5"><a href="#cb15-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="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>      attributes_of<span class="op">(^^</span>T<span class="op">)</span>,</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">[</span>deprecated<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> deprecated; <span class="op">}</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span>;</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<h1 data-number="4" id="proposed-wording"><span class="header-section-number">4</span> Proposed wording<a href="#proposed-wording" class="self-link"></a></h1>
<h2 data-number="4.1" id="language"><span class="header-section-number">4.1</span> Language<a href="#language" class="self-link"></a></h2>
<h3 class="unnumbered" id="basic.fundamental-fundamental-types"><span>6.8.2
<a href="https://wg21.link/basic.fundamental">[basic.fundamental]</a></span>
Fundamental types<a href="#basic.fundamental-fundamental-types" class="self-link"></a></h3>
<p>Augment the description of <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
found in new paragraph 17.1 to add standard attribute as a valid
representation to the current enumerated list</p>
<div class="diff">
<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">17-1</a></span> A
value of type std::meta::info is called a
<code class="sourceCode cpp"><em>reflection</em></code>. There exists a
unique <code class="sourceCode cpp"><em>null reflection</em></code>;
every other reflection is a representation of<br />
        …<br />
        <span class="add" style="color: #006e28"><ins>- an
attribute</ins></span><br />
        - a data member description (11.4.1 [class.mem.general]).</div>
</blockquote>
</div>
<p>Update 17.2 <code class="sourceCode cpp">Recommended practices</code>
to remove attributes from the list</p>
<div class="diff">
<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">17-2</a></span><code class="sourceCode cpp"><em>Recommended practice</em></code>:
Implementations are discouraged from representing any constructs
described by this document that are not explicitly enumerated in the
list above (e.g., partial template specializations, <span class="rm" style="color: #bf0303"><del>attributes,</del></span> placeholder types,
statements).</div>
</blockquote>
</div>
<h3 class="unnumbered" id="expr.reflect-the-reflection-operator">7.6.2.10* [expr.reflect] The
reflection operator<a href="#expr.reflect-the-reflection-operator" class="self-link"></a></h3>
<p>Edit <code class="sourceCode cpp"><span class="op">^^</span></code>
operator grammar for attribute reflection</p>
<blockquote>
<div class="std">
<div class="line-block"><em>reflect-expression</em>:<br />
        <code class="sourceCode cpp"><span class="op">^^</span></code>
<code class="sourceCode cpp"><span class="op">::</span></code><br />
        <code class="sourceCode cpp"><span class="op">^^</span></code>
<em>unqualified-id</em><br />
        <code class="sourceCode cpp"><span class="op">^^</span></code>
<em>qualified-id</em><br />
        <code class="sourceCode cpp"><span class="op">^^</span></code>
<em>type-id</em><br />
        <code class="sourceCode cpp"><span class="op">^^</span></code>
<em>pack-index-expression</em></div>
<div class="add" style="color: #006e28">

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

</div>
</div>
</blockquote>
<p>Add the following paragraph at the bottom of 7.6.2.10 to describe: 1)
the reflection of attributes, 2) what implementation shall yield when
reflecting unsupported attributes, 3) forbidding the reflection of <code class="sourceCode cpp"><span class="op">[[</span><span class="at">assume</span><span class="op">(</span><span class="at">conditional</span><span class="op">-</span><span class="at">expression</span><span class="op">)]]</span></code></p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span> A
<code class="sourceCode default"><em>reflect-expression</em></code> of
the form
<code class="sourceCode default">^^[[ <em>attribute</em> ]]</code>
computes a reflection of the attribute <span>9.13
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>. For an
<em>attribute-token</em> not described in this document, an
implementation ignoring such
<code class="sourceCode default"><em>attribute-token</em></code> shall
return a computed value equal to
<code class="sourceCode default">^^[[ ]]</code>.<br />
<span class="marginalizedparent"><a class="marginalized">(11.2)</a></span> For
an attribute <code class="sourceCode default">r</code> described in this
document whose
<code class="sourceCode default"><em>attribute-argument-clause</em></code>
is present and is a
<code class="sourceCode default"><em>conditional-expression</em></code>,
computing the reflection of <code class="sourceCode default">r</code> is
ill-formed.</div>
</blockquote>

</div>
<h3 class="unnumbered" id="expr.eq-equality-operators"><span>7.6.10
<a href="https://wg21.link/expr.eq">[expr.eq]</a></span> Equality
Operators<a href="#expr.eq-equality-operators" class="self-link"></a></h3>
<p>Update new paragraph between <span>7.6.10
<a href="https://wg21.link/expr.eq">[expr.eq]</a></span>/5 and /6 to add
a clause for comparing reflection of attributes and renumber
accordingly</p>
<blockquote>
<div class="std">
<div class="line-block">If both operands are of type <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>,
comparison is defined as follows:</div>
<div class="line-block">- <span class="marginalizedparent"><a class="marginalized">(5+.5)</a></span>
Otherwise, if one operand represents a direct base class relationship,
then they compare equal if and only if the other operand represents the
same direct base class relationship.</div>
<div class="add" style="color: #006e28">

<div class="line-block">- <span class="marginalizedparent"><a class="marginalized">(5+.*)</a></span>
Otherwise if one operand represents an attribute, then they compare
equal if and only if the other operand represents an attribute, both
those attributes have the same
<code class="sourceCode default"><em>attribute-token</em></code>, and if
present, both
<code class="sourceCode default"><em>attribute-argument-clause</em></code>
are equal.</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb16"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  static_assert(^^[[nodiscard]] == ^^[[nodiscard]]);</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  static_assert(^^[[nodiscard(&quot;keep me&quot;)]] == ^^[[nodiscard(&quot;keep me&quot;)]]);</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  static_assert(^^[[nodiscard(&quot;keep me&quot;)]] != ^^[[nodiscard(&quot;keep me too&quot;)]]);</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  static_assert(^^[[nodiscard(&quot;keep me&quot;)]] != ^^[[nodiscard]]);</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  static_assert(^^[[nodiscard]] != ^^[[deprecated]]);</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
<div class="line-block">- <span class="marginalizedparent"><a class="marginalized">(5+.6)</a></span>
Otherwise, both operands
<code class="sourceCode cpp">O<sub><em>1</em></sub></code> and
<code class="sourceCode cpp">O<sub><em>2</em></sub></code> represent
data member descriptions. The operands compare equal if and only if the
data member descriptions represented by
<code class="sourceCode cpp">O<sub><em>1</em></sub></code> and
<code class="sourceCode cpp">O<sub><em>2</em></sub></code> compare equal
(11.4.1 [class.mem.general]).</div>
</div>
</blockquote>
<h2 data-number="4.2" id="library"><span class="header-section-number">4.2</span> Library<a href="#library" class="self-link"></a></h2>
<h3 data-number="4.2.1" id="meta.reflection.synop-header-meta-synopsis"><span class="header-section-number">4.2.1</span> [meta.reflection.synop]
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="#meta.reflection.synop-header-meta-synopsis" class="self-link"></a></h3>
<p>Add to the [meta.reflection.queries] section from the synopsis, the
metafunction <code class="sourceCode cpp">is_attribute</code>. Add to
the new [meta.reflection.attribute] the metafunctions
<code class="sourceCode cpp">attributes_of</code> and
<code class="sourceCode cpp">appertain</code></p>
<div class="diff">
<blockquote>
<div class="line-block">…<br />
 // [meta.reflection.queries], reflection queries<br />
…</div>
<div class="add" style="color: #006e28">

<div class="line-block"><code class="sourceCode default">consteval bool is_attribute(info r);</code></div>

</div>
<div class="line-block">…<br />
 // [meta.reflection.attribute], attribute reflection<br />
…</div>
<div class="add" style="color: #006e28">

<div class="line-block"><code class="sourceCode default">consteval vector&lt;info&gt; attributes_of(info r);</code><br />
<code class="sourceCode default">template &lt;reflection_range R = initializer_list&lt;info&gt;&gt;</code><br />
<code class="sourceCode default">consteval info appertain(info r, R&amp;&amp; v);</code></div>

</div>
</blockquote>
</div>
<h3 data-number="4.2.2" id="meta.reflection.queries-reflection-queries"><span class="header-section-number">4.2.2</span> [meta.reflection.queries]
Reflection queries<a href="#meta.reflection.queries-reflection-queries" class="self-link"></a></h3>
<p>Describe the behavior for
<code class="sourceCode cpp">is_attribute</code> metafunction, returning
true for reflection of attribute and false otherwise.</p>
<div class="diff">
<blockquote>
<div class="add" style="color: #006e28">

<div class="line-block"><span class="marginalizedparent"><a class="marginalized">*</a></span> <code class="sourceCode default">consteval bool is_attribute(info r);</code><br />
<br />
<em>Returns</em>: <code class="sourceCode default">true</code> if
<code class="sourceCode default">r</code> represents an attribute.
Otherwise, <code class="sourceCode default">false</code>.<br />
</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb17"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  static_assert(is_attribute(^^[[nodiscard]]));</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
</blockquote>
</div>
<h3 data-number="4.2.3" id="meta.reflection.attribute-attribute-reflection"><span class="header-section-number">4.2.3</span> [meta.reflection.attribute]
Attribute reflection<a href="#meta.reflection.attribute-attribute-reflection" class="self-link"></a></h3>
<p>Describe the behavior for
<code class="sourceCode cpp">attributes_of</code> metafunction,
returning a sequence of reflection of each attributes appertaining to
<code class="sourceCode cpp">r</code>. The returned sequence is sorted
in implementation-specific o</p>
<div class="diff">
<blockquote>
<div class="std">
<div class="add" style="color: #006e28">

<div class="line-block"><span class="marginalizedparent"><a class="marginalized">*</a></span> <code class="sourceCode default">consteval vector&lt;info&gt; attributes_of(info r);</code><br />
<br />
<em>Returns</em>: A vector containing reflections of all attributes
appertaining to the entity represented by
<code class="sourceCode default">r</code><br />
</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb18"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  struct [[nodiscard]] Result { Success, Failure };</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  static_assert(attributes_of(^^Result).size() == 1);</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  static_assert(attributes_of(^^Result)[0] == ^^[[nodiscard]]);</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
<div class="line-block"><br />
<span class="marginalizedparent"><a class="marginalized">*</a></span>
<code class="sourceCode default">template &lt;reflection_range R = initializer_list&lt;info&gt;&gt;</code><br />
                  <code class="sourceCode default">consteval info appertain(info r, R&amp;&amp; v);</code><br />
<br />
<em>Returns</em>: Return a reflection of the entity
<code class="sourceCode default">e</code> originally described by
<code class="sourceCode default">r</code>, each attribute found in the
sequence <code class="sourceCode default">v</code> is now considered
appertaining to <code class="sourceCode default">e</code><br />
<br />
<em>Constant When</em>:
<code class="sourceCode default">dealias(r)</code> represents a class
type, variable, function, or a namespace; and
<code class="sourceCode default">is_attribute(v_i)</code> is true for
each <code class="sourceCode default">v_i</code> in
<code class="sourceCode default">v</code><br />
<br />
</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb19"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  struct Foo;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  consteval {</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>    define_aggregate(^^Foo, {});</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>  constexpr auto r = appertain(^^Foo, { ^^[[maybe_unused]] });</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>  static_assert(attributes_of(r)[0] == ^^[[maybe_unused]]);</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>  static_assert(attributes_of(^^Foo)[0] == ^^[[maybe_unused]]);</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</div>
</div>
</blockquote>
</div>
<h3 data-number="4.2.4" id="meta.reflection.names-reflection-names-and-locations"><span class="header-section-number">4.2.4</span> [meta.reflection.names],
Reflection names and locations<a href="#meta.reflection.names-reflection-names-and-locations" class="self-link"></a></h3>
<p>Update description of
<code class="sourceCode cpp">has_identifier</code> return value to be
<code class="sourceCode cpp"><span class="kw">true</span></code> for
attribute reflection and renumber accordingly</p>
<div class="diff">
<blockquote>
<div class="line-block"><code class="sourceCode cpp"><span class="kw">consteval</span> <span class="dt">bool</span> has_identifier<span class="op">(</span>info r<span class="op">)</span>;</code><br />
<br />
<span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns</em>:<br />
…<br />
<span class="marginalizedparent"><a class="marginalized">(1.*)</a></span>
<span class="add" style="color: #006e28"><ins>Otherwise, if r represents
an attribute, then
<span><code class="sourceCode default">true</code></span></ins></span><br />
<br />
<span class="marginalizedparent"><a class="marginalized">(1.10)</a></span>
Otherwise false</div>
</blockquote>
</div>
<p>Add a paragraph to <code class="sourceCode cpp">identifier_of</code>,
<code class="sourceCode cpp">u8identifier_of</code> to describe return
value of attribute reflection to be the <code class="sourceCode cpp">attribute<span class="op">-</span>token</code></p>
<div class="diff">
<blockquote>
<div class="line-block"><code class="sourceCode cpp"><span class="kw">consteval</span> string_view identifier_of<span class="op">(</span>info r<span class="op">)</span>;</code><br />
<code class="sourceCode cpp"><span class="kw">consteval</span> string_view u8identifier_of<span class="op">(</span>info r<span class="op">)</span>;</code><br />
<br />
<span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Returns</em>:<br />
…<br />
<span class="marginalizedparent"><a class="marginalized">(4.6)</a></span>
<span class="add" style="color: #006e28"><ins>Otherwise, if
<span><code class="sourceCode default">r</code></span> represents an
attribute , then the
<span><code class="sourceCode default"><em>attribute-token</em></code></span></ins></span></div>
</blockquote>
</div>
<h2 data-number="4.3" id="feature-test-macro"><span class="header-section-number">4.3</span> Feature-test macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>The attribute reflection feature is guarded behind macro, augment
<span>15.12
<a href="https://wg21.link/cpp.predefined">[cpp.predefined]</a></span></p>
<div class="diff">
<blockquote>
<div class="line-block">__cpp_impl_reflection 2025XXL<br />
<span class="add" style="color: #006e28"><ins>__cpp_impl_reflection_attributes
2025XXL</ins></span></div>
</blockquote>
</div>
<h1 data-number="5" id="feedback"><span class="header-section-number">5</span> Feedback<a href="#feedback" class="self-link"></a></h1>
<h2 data-number="5.1" id="poll"><span class="header-section-number">5.1</span> Poll<a href="#poll" class="self-link"></a></h2>
<h3 data-number="5.1.1" id="p3385r1-sg7-nov-2024-wg21-meetings-in-wroclaw"><span class="header-section-number">5.1.1</span> P3385R1: SG7, Nov 2024, WG21
meetings in Wroclaw<a href="#p3385r1-sg7-nov-2024-wg21-meetings-in-wroclaw" class="self-link"></a></h3>
<ul>
<li>SG7 encourages more work on reflection of attributes as described in
the paper: No objection to unanimous consent</li>
</ul>
<h3 data-number="5.1.2" id="p3385r2-sg7-dec-2024-telecon"><span class="header-section-number">5.1.2</span> P3385R2: SG7, Dec 2024,
Telecon<a href="#p3385r2-sg7-dec-2024-telecon" class="self-link"></a></h3>
<ul>
<li>SG7 wants to support namespaced attributes: No objection to
unanimous consent.</li>
<li>SG7 wants to support “easy” arguments of attributes: No objection to
unanimous consent.</li>
<li>SG7 wants to support arguments (full expressions) of attributes: Not
consensus.</li>
<li>SG7 considers the paper high-priority and forwards it to LEWG and
EWG for C++26: Not consensus.</li>
<li>SG7 forwards this paper to LEWG and EWG for C++29: Not
consensus.</li>
</ul>
<h3 data-number="5.1.3" id="p3385r3-sg7-feb-2025-hagenberg"><span class="header-section-number">5.1.3</span> P3385R3: SG7, Feb 2025,
Hagenberg<a href="#p3385r3-sg7-feb-2025-hagenberg" class="self-link"></a></h3>
<ul>
<li>SG7 wants to support token source type arguments: Not consensus</li>
<li>SG7 wants to forward to EWG and LEWG as is: Consensus</li>
</ul>
<h2 data-number="5.2" id="implementation"><span class="header-section-number">5.2</span> Implementation<a href="#implementation" class="self-link"></a></h2>
<p>Most of the features presented here are available on a branch <a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> that is being PR to the Bloomberg
P2996 Clang implementation. Most of the challenges <a href="#fn4" class="footnote-ref" id="fnref4" role="doc-noteref"><sup>4</sup></a> met
so far were around two elements</p>
<ul>
<li>Recovering attribute arguments. After an attribute becomes semantic,
there is not an unified way to go back to their syntactic forms and from
there, extract arguments. Our strategy (hack) was to add a backlink from
semantic to syntactic form of attributes, and extend their lifetime so
the links remain available. Arguably a better solution is to add an
accessor to <code class="sourceCode cpp">Attr</code> to recover the
arguments directly and not have this artificial backlink…</li>
<li>Splicing dependent expression. We must delay the evaluation of <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> </span><span class="op">^^</span><span class="at">T </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></code>
when <code class="sourceCode cpp">T</code> is dependent and remember to
expand the recovered attributes at instantiation. This was done by
creating a custom attribute with argument type
<code class="sourceCode cpp">expression</code>. At parse time when
meeting <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> </span><span class="op">^^</span><span class="at">T </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></code>,
we attached that custom attribute to the AST node under evaluation.
Later on when we instantiate the appertained-to entity, that custom
attribute is recovered, the dependent expression is evaluated and the
attributes extracted.</li>
</ul>
<p>Note that the second point is rather moot starting from revision 5
where <em>in-place</em> splicing of attributes was removed.</p>
<h1 data-number="6" id="conclusion"><span class="header-section-number">6</span> Conclusion<a href="#conclusion" 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 approach to tackling this
problem. However based on feedback, the concern of introspecting on
expression attributes was a topic 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="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-P1887R1" class="csl-entry" role="doc-biblioentry">
[P1887R1] Corentin Jabot. 2020-01-13. Reflection on attributes. <a href="https://wg21.link/p1887r1"><div class="csl-block">https://wg21.link/p1887r1</div></a>
</div>
<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-P2552R3" class="csl-entry" role="doc-biblioentry">
[P2552R3] Timur Doumler. 2023-06-14. On the ignorability of standard
attributes. <a href="https://wg21.link/p2552r3"><div class="csl-block">https://wg21.link/p2552r3</div></a>
</div>
<div id="ref-P2565R0" class="csl-entry" role="doc-biblioentry">
[P2565R0] Bret Brown. 2022-03-16. Supporting User-Defined Attributes. <a href="https://wg21.link/p2565r0"><div class="csl-block">https://wg21.link/p2565r0</div></a>
</div>
<div id="ref-P2996R11" class="csl-entry" role="doc-biblioentry">
[P2996R11] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2025-04-16. Reflection for
C++26. <a href="https://wg21.link/p2996r11"><div class="csl-block">https://wg21.link/p2996r11</div></a>
</div>
<div id="ref-P3254R0" class="csl-entry" role="doc-biblioentry">
[P3254R0] Brian Bi. 2024-05-22. Reserve identifiers preceded by @ for
non-ignorable annotation tokens. <a href="https://wg21.link/p3254r0"><div class="csl-block">https://wg21.link/p3254r0</div></a>
</div>
<div id="ref-P3385R2" class="csl-entry" role="doc-biblioentry">
[P3385R2] Aurelien Cassagnes, Roman Khoroshikh, Anders Johansson.
2024-12-12. Attributes reflection. <a href="https://wg21.link/p3385r2"><div class="csl-block">https://wg21.link/p3385r2</div></a>
</div>
<div id="ref-P3385R4" class="csl-entry" role="doc-biblioentry">
[P3385R4] Aurelien Cassagnes. 2025-03-11. Attributes reflection. <a href="https://wg21.link/p3385r4"><div class="csl-block">https://wg21.link/p3385r4</div></a>
</div>
</div>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Oddly enough this is what reflection
of a null statement decorated by this attribute would look like, if that
was possible.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p>Note that we are here going straight
to the subset of non standard attributes that matter the most,
implementation specific attributes. User defined arbitrary attributes
are best addressed via the annotation proposal.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p><a href="https://github.com/zebullax/clang-p2996/tree/p3385" class="uri">https://github.com/zebullax/clang-p2996/tree/p3385</a><a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn4" role="doc-endnote"><p>Those were challenges for a first
time contribution to Clang, they may not be so challenging for other
contributors.<a href="#fnref4" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
