<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2025-03-11" />
  <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>P3385R4</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-03-11</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, EWG, LEWG<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>
    </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="P3385R3">[<a href="https://wg21.link/p3385r3" role="doc-biblioref">P3385R3</a>]</span></p>
<ul>
<li>Fix typo</li>
<li>Rework wording around lookup of splice-expression</li>
<li>Update authors</li>
<li>Rebase on <span class="citation" data-cites="P2996R9">[<a href="https://wg21.link/p2996r9" role="doc-biblioref">P2996R9</a>]</span></li>
</ul>
<p>Since <span class="citation" data-cites="P3385R2">[<a href="https://wg21.link/p3385r2" role="doc-biblioref">P3385R2</a>]</span></p>
<ul>
<li>Address scoped attributes</li>
<li>Address attribute argument clause</li>
</ul>
<p>Since <span class="citation" data-cites="P3385R1">[<a href="https://wg21.link/p3385r1" role="doc-biblioref">P3385R1</a>]</span></p>
<ul>
<li>Fix various issues with samples</li>
<li>Fix wording</li>
<li>Rebase on <span class="citation" data-cites="P2996R8">[<a href="https://wg21.link/p2996r8" role="doc-biblioref">P2996R8</a>]</span></li>
</ul>
<p>Since <span class="citation" data-cites="P3385R0">[<a href="https://wg21.link/p3385r0" role="doc-biblioref">P3385R0</a>]</span></p>
<ul>
<li>Reword ignorability section to mention set of rules</li>
<li>Discuss argument clause in <code class="sourceCode cpp">info</code>
equal operator</li>
<li>Discuss appertaining to null statement in reflect expression</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>    define_aggregate<span class="op">(^^</span>MigratedUser, selectNonDeprecated<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="P2996R8">[<a href="https://wg21.link/p2996r8" role="doc-biblioref">P2996R8</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.12
<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.12
<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…</p>
<p>In the end, the current proposal aims to cover realistic use cases by
rendering ill formed the reflection of attributes with
<em>conditional-expression</em> argument clause</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. We propose the following rules/guidelines</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="P2996R8">[<a href="https://wg21.link/p2996r8" role="doc-biblioref">P2996R8</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 <em>attribute</em> 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 an empty list of 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>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="#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 any context 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 found via reflection
<code class="sourceCode cpp">r</code>. In effect every attributes that
are found via <code class="sourceCode cpp">attributes_of<span class="op">(</span>r<span class="op">)</span></code>
are expanded in place inside <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></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 shall be discussed in a separate
paper.</p>
<p>A simple example of splicer 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">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>
<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="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> enumerators_of<span class="op">(^^</span>ErrorCode<span class="op">))</span> <span class="op">{</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>,</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>      end,</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb5-14"><a href="#cb5-14" 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, the program is ill-formed,
as usual.</p>
<h3 data-number="3.3.1" id="attribute-using"><span class="header-section-number">3.3.1</span> Attribute using<a href="#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, such as in the
following example</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> attribute <span class="op">=</span> <span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span>
<span id="cb6-3"><a href="#cb6-3" 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="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"> attribute </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span> Code <span class="op">{}</span>;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>While it is unlikely the user intends 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 <em>subsequent</em> 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="#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">auto</span> attribute <span class="op">=</span> <span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span>
<span id="cb7-3"><a href="#cb7-3" 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"> attribute </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> Code <span class="op">{}</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<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 two metafunctions to what has already been
discussed in <span class="citation" data-cites="P2996R8">[<a href="https://wg21.link/p2996r8" role="doc-biblioref">P2996R8</a>]</span>. In addition, we will add
support for 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="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> 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="#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 a vector of reflections representing individual
attributes that were appertaining to reflected upon entity.</p>
<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="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">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb9-3"><a href="#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="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-5"><a href="#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 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.</p>
<h3 data-number="3.4.3" id="identifier_of-display_string_of"><span class="header-section-number">3.4.3</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="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="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> <span class="dt">int</span> func<span class="op">()</span>;</span>
<span id="cb10-3"><a href="#cb10-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="cb10-4"><a href="#cb10-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="cb10-5"><a href="#cb10-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="cb10-6"><a href="#cb10-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.4" id="data_member_spec-define_aggregate"><span class="header-section-number">3.4.4</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 will change thusly:</p>
<div>
<div class="sourceCode" id="cb11"><pre class="sourceCode diff"><code class="sourceCode diff"><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>    namespace std::meta {</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>      struct data_member_options {</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>        struct name_type {</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;u8string, T&gt;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;string, T&gt;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>        optional&lt;name_type&gt; name;</span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; alignment;</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; bit_width;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="st">-       bool no_unique_address = false;</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a><span class="va">+       vector&lt;info&gt;  attributes;</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>      };</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb11-19"><a href="#cb11-19" 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="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="kw">struct</span> Empty <span class="op">{}</span>;</span>
<span id="cb12-3"><a href="#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="#cb12-4" aria-hidden="true" tabindex="-1"></a>    define_aggregate<span class="op">(^^</span>S, <span class="op">{</span></span>
<span id="cb12-5"><a href="#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">&quot;i&quot;</span><span class="op">})</span>,</span>
<span id="cb12-6"><a href="#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">&quot;e&quot;</span>, </span>
<span id="cb12-7"><a href="#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="#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Equivalent to</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// struct [[nodiscard]] S {</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   int i;</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   [[no_unique_address]] struct Empty { } e;</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// };</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Note here that <span class="citation" data-cites="P2996R8">[<a href="https://wg21.link/p2996r8" role="doc-biblioref">P2996R8</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, as we wish to keep the scope of change rather
small.</p>
<h3 data-number="3.4.5" id="other-metafunctions"><span class="header-section-number">3.4.5</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="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><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>    <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="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#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="#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="#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="#cb13-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">[</span>attributes<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> attributes<span class="op">[</span><span class="dv">0</span><span class="op">]</span>; <span class="op">}</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span>;</span>
<span id="cb13-9"><a href="#cb13-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.12
<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">_attribute-token_</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="cb14"><pre class="sourceCode default cpp"><code class="sourceCode default"><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>static_assert(^^[[nodiscard]] == ^^[[nodiscard]]);</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>static_assert(^^[[nodiscard(&quot;keep me&quot;)]] == ^^[[nodiscard(&quot;keep me&quot;)]]);</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>static_assert(^^[[nodiscard(&quot;keep me&quot;)]] != ^^[[nodiscard(&quot;keep me too&quot;)]]);</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>static_assert(^^[[nodiscard(&quot;keep me&quot;)]] != ^^[[nodiscard]]);</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>static_assert(^^[[nodiscard]] != ^^[[deprecated]]);</span>
<span id="cb14-7"><a href="#cb14-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>
<h3 class="unnumbered" id="dcl.attr.grammar-attribute-syntax-and-semantics"><span>9.12.1
<a href="https://wg21.link/dcl.attr.grammar">[dcl.attr.grammar]</a></span>
Attribute syntax and semantics<a href="#dcl.attr.grammar-attribute-syntax-and-semantics" class="self-link"></a></h3>
<p>Change the grammar to allow a<code class="sourceCode cpp">splice<span class="op">-</span>specifier</code>
inside <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></code></p>
<blockquote>
<div class="diff">
<div class="line-block">        …<br />
<em>attribute-specifier</em>:<br />
        [ [ <em>attribute-using-prefix<sub>opt</sub></em>
<em>attribute-list</em> ] ]</div>
<div class="add" style="color: #006e28">

<div class="line-block">        [ [ <em>splice-specifier</em> ] ]</div>

</div>
</div>
</blockquote>
<p>Modify the paragraph 5 to relax appertainance rules when an attribute
is the operand of a reflection expression.</p>
<div class="diff">
<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">5</a></span> <span class="add" style="color: #006e28"><ins>Outside a
<span><code class="sourceCode default"><em>reflect-expression</em></code></span>,
each</ins></span><span class="rm" style="color: #bf0303"><del>Each</del></span>
<code class="sourceCode cpp"><em>attribute-specifier-seq</em></code> is
said to appertain to some entity or statement, identified by the
syntactic context where it appears (Clause 8, Clause 9, 9.3). If an
<code class="sourceCode cpp"><em>attribute-specifier-seq</em></code>
that appertains to some entity or statement contains an
<code class="sourceCode cpp"><em>attribute</em></code> or
<code class="sourceCode cpp"><em>alignment-specifier</em></code> that is
not allowed to apply to that entity or statement, the program is
ill-formed. If an
<code class="sourceCode cpp"><em>attribute-specifier-seq</em></code>
appertains to a friend declaration (11.8.4), that declaration shall be a
definition.</div>
</blockquote>
</div>
<p>Modify the paragraph 7 to allow consecutive left square brackets
following the reflection operator
<code class="sourceCode cpp"><span class="op">^^</span></code></p>
<div class="diff">
<blockquote>
<div class="line-block"><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 when computing the
reflection of an attribute the operand
<span><code class="sourceCode default"><em>reflect-expression</em></code></span>
(7.6.2.10 [expr.reflect])</ins></span>.</div>
</blockquote>
</div>
<p>Add the following paragraph to describe the process of resolving the
entity identified by the splice specifier found inside <code class="sourceCode cpp"><span class="op">[[</span><span class="at"> </span><span class="op">]]</span></code>,
and extracting attributes from the reflected entity</p>
<blockquote>
<div class="std">
<div class="add" style="color: #006e28">

<div class="line-block"><span class="marginalizedparent"><a class="marginalized">8</a></span> For an
<code class="sourceCode default"><em>attribute-specifier</em></code>
containing a
<code class="sourceCode default">splice-specifier</code><br />
- The construct <code class="sourceCode default">S</code> designated by
the <code class="sourceCode default"><em>splice-specifier</em></code>
and the referred to expression is matched as described per
[expr.prim.splice] 7.5.8-2<br />
- If the expression <code class="sourceCode default">S</code> found is
not ill-formed, every attributes appertaining to
<code class="sourceCode default">S</code> is now considered appertaining
to the entity the original
<code class="sourceCode default"><em>attribute-specifier</em></code>
appertains to.</div>
<div class="example">
<span>[ <em>Example:</em> </span>
<div class="sourceCode" id="cb15"><pre class="sourceCode default cpp"><code class="sourceCode default"><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>struct [[nodiscard(&quot;keep me&quot;), maybe_unused]] Foo;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>struct [[ [: ^^Foo :] ]] Bar; // same as &quot;struct [[nodiscard(&quot;keep me&quot;), maybe_unused]] Bar;&quot;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>

</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
two metafunctions <code class="sourceCode cpp">is_attribute</code> and
<code class="sourceCode cpp">attributes_of</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><br />
<code class="sourceCode default">consteval vector&lt;info&gt; attributes_of(info r);</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>
<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">42</a></span> <code class="sourceCode cpp"><span class="kw">consteval</span> <span class="dt">bool</span> is_attribute<span class="op">(</span>info r<span class="op">)</span>;</code><br />
<br />
Returns:
<code class="sourceCode cpp"><span class="kw">true</span></code> if
<code class="sourceCode cpp">r</code> represents a standard attribute.
Otherwise,
<code class="sourceCode cpp"><span class="kw">false</span></code>.<br />
<br />
<span class="marginalizedparent"><a class="marginalized">43</a></span>
<code class="sourceCode cpp"><span class="kw">consteval</span> vector<span class="op">&lt;</span>info<span class="op">&gt;</span> attributes_of<span class="op">(</span>info r<span class="op">)</span>;</code><br />
<br />
Returns: A vector containing reflections of all attributes appertaining
to the entity represented by <code class="sourceCode cpp">r</code></div>
</blockquote>
<h3 data-number="4.2.3" id="meta.reflection.names-reflection-names-and-locations"><span class="header-section-number">4.2.3</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
reflected attribute 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 reflected attribute</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.11
<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: No consense</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 met so far were about
recovering arguments for attributes at splice time. 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.</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-P2996R8" class="csl-entry" role="doc-biblioentry">
[P2996R8] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-12-17. Reflection for
C++26. <a href="https://wg21.link/p2996r8"><div class="csl-block">https://wg21.link/p2996r8</div></a>
</div>
<div id="ref-P2996R9" class="csl-entry" role="doc-biblioentry">
[P2996R9] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2025-01-13. Reflection for
C++26. <a href="https://wg21.link/p2996r9"><div class="csl-block">https://wg21.link/p2996r9</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-P3385R0" class="csl-entry" role="doc-biblioentry">
[P3385R0] Aurelien Cassagnes, Aurelien Cassagnes, Roman Khoroshikh,
Anders Johansson. 2024-09-16. Attributes reflection. <a href="https://wg21.link/p3385r0"><div class="csl-block">https://wg21.link/p3385r0</div></a>
</div>
<div id="ref-P3385R1" class="csl-entry" role="doc-biblioentry">
[P3385R1] Aurelien Cassagnes, Roman Khoroshikh, Anders Johansson.
2024-10-15. Attributes reflection. <a href="https://wg21.link/p3385r1"><div class="csl-block">https://wg21.link/p3385r1</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-P3385R3" class="csl-entry" role="doc-biblioentry">
[P3385R3] Aurelien Cassagnes, Roman Khoroshikh, Anders Johansson.
2025-01-07. Attributes reflection. <a href="https://wg21.link/p3385r3"><div class="csl-block">https://wg21.link/p3385r3</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>https://github.com/zebullax/clang-p2996/tree/p3385<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
