<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-12-12" />
  <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>P3385R2</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-12-12</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      sg7<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Aurelien Cassagnes<br>&lt;<a href="mailto:aurelien.cassagnes@gmail.com" class="email">aurelien.cassagnes@gmail.com</a>&gt;<br>
      Roman Khoroshikh<br>&lt;<a href="mailto:rkhoroshikh@bloomberg.net" class="email">rkhoroshikh@bloomberg.net</a>&gt;<br>
      Anders Johansson<br>&lt;<a href="mailto:ajohansson12@bloomberg.net" class="email">ajohansson12@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</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="#optionality-rule" id="toc-optionality-rule"><span class="toc-section-number">2.3</span> 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="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 2996R8</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>Rebase on <span class="citation" data-cites="P2996R7">[<a href="https://wg21.link/p2996r7" role="doc-biblioref">P2996R7</a>]</span></li>
<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 likely will be new
attributes added as the language evolves.<br />
As reflection makes its way into our standard, what is missing is 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>vector<span class="op">&lt;</span>info<span class="op">&gt;</span> selectNonDeprecated<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="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-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>      keepLive<span class="op">(</span>member<span class="op">)</span>;</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> liveMembers;</span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Migrated user will no longer support deprecated fields</span></span>
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> MigratedUser;</span>
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a>  define_aggregate<span class="op">(^^</span>MigratedUser, selectNonDeprecated<span class="op">())</span>;</span>
<span id="cb1-30"><a href="#cb1-30" 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="P2996R7">[<a href="https://wg21.link/p2996r7" role="doc-biblioref">P2996R7</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>
<p>Attributes are colloquially split into standard and non-standard.
This proposal wishes to limit itself to standard attributes (<span>9.12
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>). We feel
that since it is up to the implementation to define how to handle
non-standard attributes, it would lead to obscure situations that we
don’t claim to tackle here.<br />
A fairly simple (admittedly artificial) example can be built as such:
Given an implementation supporting a non-standard <code class="sourceCode cpp"><span class="op">[[</span><span class="at">privacy</span><span class="op">::</span><span class="at">no_reflection</span><span class="op">]]</span></code>
attributes that suppresses all reflection information appertaining to an
entity, we would have a hard time coming up with a self-consistent
system of rules to start with.<br />
</p>
<p>Henceforth, in this proposal, ‘attributes’, ‘standard attributes’ are
all meant to be equivalent terms for attributes described by the
standard.</p>
<h2 data-number="2.3" id="optionality-rule"><span class="header-section-number">2.3</span> Optionality rule<a href="#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. This proposal agrees with the discussion carried on there and in
<span class="citation" data-cites="CWG2538">[<a href="https://wg21.link/cwg2538" role="doc-biblioref">CWG2538</a>]</span>. We also feel that whether an
implementation decides to semantically ignore a standard attribute
should not matter.<br />
</p>
<p>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>What matters more is the following set of rules that aim to discuss
self-consistency</p>
<ul>
<li>We should be able to statically reflect on appertaining attributes
even if ignored: Implementations are required to parse and check
syntactic rules related to attributes. Whether they are ignored
semantically later on should not mean that they are removed from the
source code during translation<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</li>
<li>Splicing attributes on a declaration should be undistinguishable
from appertaining those attributes to this declaration.</li>
</ul>
<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="P2996R7">[<a href="https://wg21.link/p2996r7" role="doc-biblioref">P2996R7</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="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="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 argument clause if
any. If the <em>attribute</em> is not a standard attribute, the
expression is ill-formed.</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="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="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">last</code> enumerator while preserving the
original attributes:</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>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> ErrorCode <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>      warn,</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>      fatal,</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="op">[:</span><span class="at"> </span><span class="op">^^</span><span class="at">ErrorCode </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">enum</span> <span class="kw">class</span> ClosedErrorCode <span class="op">{</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>      begin,</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>      <span class="kw">template</span> <span class="cf">for</span> <span class="op">(</span><span class="kw">constexpr</span> <span class="kw">auto</span> e <span class="op">:</span> enumerators_of<span class="op">(^^</span>ErrorCode<span class="op">))</span> <span class="op">{</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">[:</span>e<span class="op">:]</span>,</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>      last,</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>If the attributes produced through introspection violate the rules of
what attributes can appertain to what entity, 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="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">auto</span> attribute <span class="op">=</span> <span class="op">^^[[</span><span class="at">nodiscard</span><span class="op">]]</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">[[</span><span class="at"> </span><span class="kw">using</span><span class="at"> CC</span><span class="op">:</span><span class="at"> debug</span>,<span class="at"> </span><span class="op">[:</span><span class="at"> attribute </span><span class="op">:]</span><span class="at"> </span><span class="op">]]</span> <span class="kw">enum</span> <span class="kw">class</span> Code <span class="op">{}</span>;</span>
<span id="cb5-4"><a href="#cb5-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="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="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> <span class="kw">enum</span> <span class="kw">class</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>
<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="P2996R7">[<a href="https://wg21.link/p2996r7" role="doc-biblioref">P2996R7</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="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">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>        <span class="kw">consteval</span> <span class="kw">auto</span> 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="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb7-5"><a href="#cb7-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="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.</p>
<h3 data-number="3.4.3" id="identifier_of-display_identifier_of"><span class="header-section-number">3.4.3</span> identifier_of,
display_identifier_of<a href="#identifier_of-display_identifier_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="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="op">[[</span><span class="at">nodiscard</span><span class="op">]]</span> <span class="dt">int</span> func<span class="op">()</span>;</span>
<span id="cb9-3"><a href="#cb9-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="cb9-4"><a href="#cb9-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="cb9-5"><a href="#cb9-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="cb9-6"><a href="#cb9-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_identifier_of<span class="op">(</span>r<span class="op">)</span></code>
(resp. <code class="sourceCode cpp">u8display_identifier_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">discard</code> as it might be
more striking for display purpose to the user.</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 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="cb10"><pre class="sourceCode diff"><code class="sourceCode diff"><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>    namespace std::meta {</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>      struct data_member_options {</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>        struct name_type {</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;u8string, T&gt;</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>          template &lt;typename T&gt; requires constructible_from&lt;string, T&gt;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>            consteval name_type(T &amp;&amp;);</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>        };</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>        optional&lt;name_type&gt; name;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; alignment;</span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a>        optional&lt;int&gt; bit_width;</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="st">-       bool no_unique_address = false;</span></span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a><span class="va">+       vector&lt;info&gt;  attributes;</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a>      };</span>
<span id="cb10-18"><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb10-19"><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
</div>
<p>From there building an aggregate piecewise proceeds as usual</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> Empty <span class="op">{}</span>;</span>
<span id="cb11-3"><a href="#cb11-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="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    define_aggregate<span class="op">(^^</span>S, <span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-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="cb11-6"><a href="#cb11-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="cb11-7"><a href="#cb11-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="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Equivalent to</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// struct [[nodiscard]] S {</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   int i;</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   [[no_unique_address]] struct Empty { } e;</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// };</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span></code></pre></div>
<p>Note here that <span class="citation" data-cites="P2996R7">[<a href="https://wg21.link/p2996r7" role="doc-biblioref">P2996R7</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 poorly in that every new attributes introduced
into the standard will lead to discussions on whether or not they
deserve to be included in
<code class="sourceCode cpp">data_member_options</code>. There is also
little explanations as to why those were picked among all. Attaching
attributes through above 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 but in a follow-up paper, as we
wish to keep the scope of change rather small in our proposal.</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="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">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="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-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="cb12-5"><a href="#cb12-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="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>      attributes_of<span class="op">(^^</span>T<span class="op">)</span>,</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">[</span>deprecatedAttribute<span class="op">]</span> <span class="op">(</span><span class="kw">auto</span> meta<span class="op">)</span> <span class="op">{</span> meta <span class="op">==</span> attributes<span class="op">[</span><span class="dv">0</span><span class="op">]</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></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
described in this document</ins></span><br />
        - an implementation-defined construct not otherwise specified by
this document.</div>
</blockquote>
</div>
<p>Update 17.2
<code class="sourceCode cpp">Recommended practices</code></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 to allow reflecting over an attribute</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</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">8</a></span> A
<code class="sourceCode default"><em>reflect-expression</em></code>
having the form
<code class="sourceCode default">^^ [[ attribute ]]</code> computes a
reflection of the attribute <span>9.12
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>. If
<em>attribute</em> is not described in <span>9.12
<a href="https://wg21.link/dcl.attr">[dcl.attr]</a></span>, the behavior
is implementation defined.</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">(*.7)</a></span>
Otherwise, if one operand represents a
<code class="sourceCode cpp"><em>base-specifier</em></code>, then they
compare equal if and only if the other operand represents the same
<code class="sourceCode cpp"><em>base-specifier</em></code>.<br />
- <span class="marginalizedparent"><a class="marginalized">(*.)</a></span> <span class="add" style="color: #006e28"><ins>Otherwise if one operand
represents an attribute described in this document, then they compare
equal if and only if the other operand represents an attribute as well
and both those attributes share the same
<span><code class="sourceCode default"><em>identifier</em></code></span>.</ins></span></div>
<div class="line-block">- <span class="marginalizedparent"><a class="marginalized">(*.8)</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
descriptions of declarations of non-static data members: Let
<code class="sourceCode cpp">C<sub><em>1</em></sub></code> and
<code class="sourceCode cpp">C<sub><em>2</em></sub></code> be invented
class types such that each
<code class="sourceCode cpp">C<sub><em>k</em></sub></code> has a single
non-static data member having the properties described by
<code class="sourceCode cpp">O<sub><em>k</em></sub></code>. The operands
compare equal if and only if the data members of
<code class="sourceCode cpp">C<sub><em>1</em></sub></code> and
<code class="sourceCode cpp">C<sub><em>2</em></sub></code> would be
declared with the same type or
<code class="sourceCode cpp"><em>typedef-name</em></code>, name (if
any), <code class="sourceCode cpp"><em>alignment-specifiers</em></code>
(if any), width, and attributes</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 <code class="sourceCode cpp">splice<span class="op">-</span>specifier</code>
inside <code class="sourceCode cpp"><span class="op">[</span> <span class="op">[</span> <span class="op">]</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 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</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 as an operand of a
<span><code class="sourceCode default"><em>reflect-expression</em></code></span></ins></span>.</div>
</blockquote>
</div>
<p>Add the following paragraph</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="line-block"><span class="marginalizedparent"><a class="marginalized">8</a></span> If an
<code class="sourceCode default"><em>attribute-specifier</em></code>
contains a <code class="sourceCode default">splice-specifier</code>,
every attribute contained in that reflection appertain to the entity to
which that
<code class="sourceCode default"><em>attribute-specifier</em></code>
appertain.<br />
<br />
[ Example 1:<br />
<br />
  <code class="sourceCode default">struct [[nodiscard, maybe_unused]] Foo;</code><br />
  <code class="sourceCode default">struct [[ [: ^^Foo :] ]] Bar; // same as struct [[nodiscard, maybe_unused]] Bar;</code><br />
<br />
— end example ]</div>
</blockquote>

</div>
<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 of 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>
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 />
<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 features 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 2024XXL<br />
<span class="add" style="color: #006e28"><ins>__cpp_impl_reflection_attributes
2024XXL</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>
<p>Poll: P3385R1: SG7 encourages more work on reflection of attributes
as described in the paper.</p>
<p><em>Unanimous consent</em></p>
<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>Features proposed here were implemented on a public fork (off the
Bloomberg P2996 branch) of Clang. Although it isn’t production ready
code it demonstrates the feasability of the proposal.</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-CWG2538" class="csl-entry" role="doc-biblioentry">
[CWG2538] Jens Maurer. 2021-12-02. Can standard attributes be
syntactically ignored? <a href="https://wg21.link/cwg2538"><div class="csl-block">https://wg21.link/cwg2538</div></a>
</div>
<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-P2996R7" class="csl-entry" role="doc-biblioentry">
[P2996R7] Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton,
Faisal Vali, Daveed Vandevoorde, Dan Katz. 2024-10-13. Reflection for
C++26. <a href="https://wg21.link/p2996r7"><div class="csl-block">https://wg21.link/p2996r7</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>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>Discussion in
https://eel.is/c++draft/dcl.attr#depend-2, imply that translation units
need to carry their attributes unchanged to observe that rule.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
