<!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-17" />
  <title>Overload resolution hook: declcall( unevaluated-call-expression
)</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">Overload resolution hook:
declcall( unevaluated-call-expression )</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2825R5</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-03-17</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG<br>
      CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Gašper Ažman<br>&lt;<a href="mailto:gasper.azman@gmail.com" class="email">gasper.azman@gmail.com</a>&gt;<br>
      Bronek Kozicki<br>&lt;<a href="mailto:brok@spamcop.net" class="email">brok@spamcop.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="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision
History<span></span></a></li>
<li><a href="#motivation-and-prior-art" id="toc-motivation-and-prior-art"><span class="toc-section-number">3</span> Motivation and Prior
Art<span></span></a>
<ul>
<li><a href="#related-work" id="toc-related-work"><span class="toc-section-number">3.1</span> Related Work<span></span></a></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">4</span> Proposal<span></span></a>
<ul>
<li><a href="#interesting-cases-in-the-above-example" id="toc-interesting-cases-in-the-above-example"><span class="toc-section-number">4.1</span> Interesting cases in the above
example<span></span></a></li>
<li><a href="#pointers-to-virtual-member-functions" id="toc-pointers-to-virtual-member-functions"><span class="toc-section-number">4.2</span> Pointers to virtual member
functions<span></span></a></li>
<li><a href="#alternatives-to-syntax" id="toc-alternatives-to-syntax"><span class="toc-section-number">4.3</span> Alternatives to
syntax<span></span></a></li>
<li><a href="#naming" id="toc-naming"><span class="toc-section-number">4.4</span> Naming<span></span></a></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">5</span> Implementation
experience<span></span></a></li>
<li><a href="#usecases" id="toc-usecases"><span class="toc-section-number">6</span> Usecases<span></span></a>
<ul>
<li><a href="#what-does-this-give-us-that-we-dont-have-yet" id="toc-what-does-this-give-us-that-we-dont-have-yet"><span class="toc-section-number">6.1</span> What does this give us that we
don’t have yet<span></span></a></li>
<li><a href="#thats-not-good-enough-to-do-all-that-work.-what-else" id="toc-thats-not-good-enough-to-do-all-that-work.-what-else"><span class="toc-section-number">6.2</span> That’s not good enough to do all
that work. What else?<span></span></a></li>
</ul></li>
<li><a href="#guidance-given" id="toc-guidance-given"><span class="toc-section-number">7</span> Guidance Given:<span></span></a>
<ul>
<li><a href="#reflection-1" id="toc-reflection-1"><span class="toc-section-number">7.1</span> Reflection?<span></span></a></li>
<li><a href="#unevaluated-operands-only" id="toc-unevaluated-operands-only"><span class="toc-section-number">7.2</span> Unevaluated operands
only?<span></span></a></li>
</ul></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">8</span> Proposed
Wording<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">9</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">10</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>This paper introduces a new expression into the language
<code class="sourceCode default">declcall(<em>expression</em>)</code>.</p>
<p>The <code class="sourceCode default">declcall</code> expression is a
constant expression of type pointer-to-function (PF) or
pointer-to-member-function (PMF). Its value is the pointer to the
function that would have been invoked if the <em>expression</em> were
evaluated. The <em>expression</em> itself is an unevaluated operand.</p>
<p>In effect, <code class="sourceCode default">declcall</code> is a hook
into the overload resolution machinery.</p>
<h1 data-number="2" id="revision-history"><span class="header-section-number">2</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<ol start="0" type="1">
<li>new paper!</li>
<li>seen as <code class="sourceCode default">calltarget</code> in
EWGi</li>
<li><code class="sourceCode default">calltarget</code> was a bad name,
and design refined</li>
<li>Seen in EWG as <code class="sourceCode default">declcall</code>,
well received, must come back</li>
<li>Added core wording and got it reviewed, more revisions. Added
devirtualized pointers to member functions.</li>
<li><ul>
<li>Expanded motivation section</li>
<li>resolved design question re. devirtualized pointers</li>
<li>corrections from wording review from CWG, specifically Hubert
Tong’s</li>
<li>New section for EWG: resolve questions around comparison between
devirtualized pointer values and
<code class="sourceCode default">final</code> functions</li>
<li>added section about implementation experience</li>
</ul></li>
</ol>
<h1 data-number="3" id="motivation-and-prior-art"><span class="header-section-number">3</span> Motivation and Prior Art<a href="#motivation-and-prior-art" class="self-link"></a></h1>
<p>The language facilities for overload resolution that aren’t the
actual call syntax have severe limitations.</p>
<p>The facilities available as of C++23 are:</p>
<ul>
<li>assignment to a variable or parameter of a given function pointer
type</li>
<li><code class="sourceCode default">static_cast&lt;function_pointer_type&gt;(function_identifier)</code></li>
<li><code class="sourceCode default">&amp;function_name</code> (if not
overload set)</li>
</ul>
<p>All of these are unsuitable for ad-hoc type-erasure that library
authors (such as <span class="citation" data-cites="P2300R6">[<a href="#ref-P2300R6" role="doc-biblioref">P2300R6</a>]</span>) need
whenever implicit conversions may be involved in any form.</p>
<p>We can sometimes indirect through a lambda to “remember” the result
of an overload resolution to be invoked later, if the function pointer
type is not a perfect match:</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 class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> my_erased_wrapper <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> fptr_t <span class="op">=</span> R<span class="op">(*)(</span>Args<span class="op">...)</span>;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  fptr_t erased;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="co">// for some types R, T1, T2, T3</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>my_erased_wrapper<span class="op">&lt;</span>R, T1, T2, T3<span class="op">&gt;</span> vtable <span class="op">=</span> <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">+[](</span>T1 a, T2 b, T3 c<span class="op">)</span> <span class="op">-&gt;</span> R <span class="op">{</span> <span class="cf">return</span> some_f<span class="op">(</span>FWD<span class="op">(</span>a<span class="op">)</span>, FWD<span class="op">(</span>b<span class="op">)</span>, FWD<span class="op">(</span>c<span class="op">))</span>; <span class="op">}</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>… however, this does not work in all cases, and has suboptimal code
generation.</p>
<ul>
<li>it introduces a whole new lambda scope
<ul>
<li>expensive for optimizers because extra inlining</li>
<li>annoying for debugging because of an extra stack frame</li>
<li>decays arguments prematurely or reifies prvalues both of which
inhibit copy-elision</li>
<li>cause unnecessary template instantiations through value-category
combinations of deduced parameters</li>
</ul></li>
<li>it places additional unwelcome requirements on the programmer, who
must:
<ul>
<li>divine the correct
<code class="sourceCode default">noexcept(which?)</code></li>
<li>explicitly (and correctly) spell the return type of the erased
function</li>
<li>explicitly (and correctly) spell out the exact parameter types of
the forwarded function</li>
</ul></li>
<li>if one fails to do the above, one must at least ensure that
<ul>
<li>arguments are convertible</li>
<li>return type is convertible</li>
<li>… both of which result in suboptimal codegen</li>
</ul></li>
<li>Nested erasures do not flatten: we cannot subset type-erased
wrappers (we can’t divine an exact match in the presence of overloads)
(think “subsetting vtables”)</li>
</ul>
<p>Oh, if only we had a facility to ask the compiler what function we’d
be calling and then <em>just have a pointer to it</em>.</p>
<p>This is what this paper is trying to provide.</p>
<h2 data-number="3.1" id="related-work"><span class="header-section-number">3.1</span> Related Work<a href="#related-work" class="self-link"></a></h2>
<h3 data-number="3.1.1" id="reflection"><span class="header-section-number">3.1.1</span> Reflection<a href="#reflection" class="self-link"></a></h3>
<p>The reflection proposal does not include anything like this. It knows
how to reflect on constants, but a general-purpose feature like this is
beyond its reach. Source: hallway discussion with Daveed
Vandevoorde.</p>
<p>We probably need to do the specification work of this paper to
understand the corner cases of even trying to do this with
reflection.</p>
<p>Reflection (<span class="citation" data-cites="P2320R0">[<a href="#ref-P2320R0" role="doc-biblioref">P2320R0</a>]</span>,<span class="citation" data-cites="P1240R1">[<a href="#ref-P1240R1" role="doc-biblioref">P1240R1</a>]</span>,<span class="citation" data-cites="P2237R0">[<a href="#ref-P2237R0" role="doc-biblioref">P2237R0</a>]</span>,<span class="citation" data-cites="P2087R0">[<a href="#ref-P2087R0" role="doc-biblioref">P2087R0</a>]</span>,<span class="citation" data-cites="N4856">[<a href="#ref-N4856" role="doc-biblioref">N4856</a>]</span>) might miss C++26, and is far
wider in scope as another
<code class="sourceCode default">decltype</code>-ish proposal that’s
easily implementable today, and
<code class="sourceCode default">std::execution</code> could use
immediately.</p>
<p>Regardless of how we chose to provide this facility, it is dearly
needed, and should be provided by the standard library or a
built-in.</p>
<p>See the <a href="#alternatives-to-syntax">Alternatives to Syntax</a>
chapter for details.</p>
<h3 data-number="3.1.2" id="library-fundamentals-ts-v3"><span class="header-section-number">3.1.2</span> Library fundamentals TS v3<a href="#library-fundamentals-ts-v3" class="self-link"></a></h3>
<p>The <a href="https://cplusplus.github.io/fundamentals-ts/v3.html#meta.trans.other">Library
Fundamentals TS version 3</a> defines <code class="sourceCode default">invocation_type&lt;F(Args...)&gt;</code> and
<code class="sourceCode default">raw_invocation_type&lt;F(Args...)&gt;</code>
with the hope of getting the function pointer type of a given call
expression.</p>
<p>However, this is not good enough to actually be able to resolve that
call in all cases.</p>
<p>Observe:</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">struct</span> S <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">void</span> f<span class="op">(</span>S<span class="op">)</span> <span class="op">{}</span> <span class="co">// #1</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> f<span class="op">(</span><span class="kw">this</span> S<span class="op">)</span> <span class="op">{}</span>   <span class="co">// #2</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> h<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">void</span><span class="op">(*)(</span>S<span class="op">)&gt;(</span>S<span class="op">::</span>f<span class="op">)</span> <span class="co">// error, ambiguous</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  S<span class="op">{}.</span>f<span class="op">(</span>S<span class="op">{})</span>; <span class="co">// calls #1</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  S<span class="op">{}.</span>f<span class="op">()</span>; <span class="co">// calls #2</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// no ambiguity for declcall</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>S<span class="op">{}.</span>f<span class="op">(</span>S<span class="op">{}))</span>; <span class="co">// &amp;#1</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>S<span class="op">{}.</span>f<span class="op">())</span>;    <span class="co">// &amp;#2</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A library solution can’t give us this, no matter how much we try,
unless we can reflect on unevaluated operands (which Reflection
does).</p>
<h1 data-number="4" id="proposal"><span class="header-section-number">4</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>We propose a new (technically) non-overloadable operator (because
<code class="sourceCode default">sizeof</code> is one, and this behaves
similarly):</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>declcall<span class="op">(</span><em>expression</em><span class="op">)</span>;</span></code></pre></div>
<p>Example:</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="dt">int</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>;  <span class="co">// 1</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span><span class="dt">long</span><span class="op">)</span>; <span class="co">// 2</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> fptr_to_1 <span class="op">=</span> declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">2</span><span class="op">))</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> fptr_to_2 <span class="op">=</span> declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">2</span><span class="bu">l</span><span class="op">))</span>;</span></code></pre></div>
<p>The program is ill-formed if the named
<code class="sourceCode default"><em>postfix-expression</em></code> is
not a call to a function (such as when it is a constructor, destructor,
built-in, etc.). Inventing functions should be a facility built in a
library <em>on top</em> of
<code class="sourceCode default">declcall</code>.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> S <span class="op">{}</span>;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>declcall<span class="op">(</span>S<span class="op">())</span>; <span class="co">// Error, constructors are not addressable</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>declcall<span class="op">(</span><span class="fu">__builtin_unreachable</span><span class="op">())</span>; <span class="co">// Error, not addressable</span></span></code></pre></div>
<p><code class="sourceCode default">declcall(expr)</code> should always
be a compile-time constant, and
<code class="sourceCode default">expr</code> always unevaluated. If the
expression is valid, but figuring out the function pointer would have
required evaluating parts of the expression, such as when calling
through a pointer to function or a surrogate function, we specify that
<code class="sourceCode default">declcall(expr)</code> is only legal to
use inside other unevaluated contexts that only care about the type,
such as <code class="sourceCode default">sizeof()</code> and
<code class="sourceCode default">decltype()</code>. Specifically, we say
that in such cases, it is not a constant expression, and its value is
unspecified.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> fptr_t <span class="op">=</span> <span class="dt">int</span> <span class="op">(*)(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> fptr_t fptr <span class="op">=</span> declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">2</span><span class="op">))</span>; <span class="co">// OK</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>declcall<span class="op">(</span>fptr<span class="op">(</span><span class="dv">2</span><span class="op">))</span>; <span class="co">// Error, fptr_to_1 is a pointer</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> T <span class="op">{</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> fptr_t<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> fptr; <span class="op">}</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>declcall<span class="op">(</span>T<span class="op">{}(</span><span class="dv">2</span><span class="op">))</span>; <span class="co">// Error, T{} would need to be evaluated</span></span></code></pre></div>
<p>If the
<code class="sourceCode default">declcall(<em>expression</em>)</code> is
evaluated and not a constant expression, the program is ill-formed (but
SFINAE-friendly).</p>
<p>However, if it is unevaluated, it’s not an error, because the type of
the expression is useful as the type argument to
<code class="sourceCode default">static_cast</code>!</p>
<p>Example:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> fptr_t <span class="op">=</span> <span class="dt">int</span> <span class="op">(*)(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> fptr_t fptr <span class="op">=</span> declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">2</span><span class="op">))</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declcall<span class="op">(</span>fptr<span class="op">(</span><span class="dv">2</span><span class="op">)))&gt;(</span>fptr<span class="op">)</span>; <span class="co">// OK, fptr, though redundant</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> T <span class="op">{</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> fptr_t<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> fptr; <span class="op">}</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declcall<span class="op">(</span>T<span class="op">{}(</span><span class="dv">2</span><span class="op">)))&gt;(</span>T<span class="op">{})</span>; <span class="co">// OK, fptr</span></span></code></pre></div>
<p>This pattern covers all cases that need evaluated operands, while
making it explicit that the operand is evaluated due to the
<code class="sourceCode default">static_cast</code>.</p>
<p>This division of labor is important - we do not want a language
facility where the operand is conditionally evaluated or
unevaluated.</p>
<p>Examples:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">(</span><span class="dt">long</span> x<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> x<span class="op">+</span><span class="dv">1</span>; <span class="op">}</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">()</span> <span class="op">{}</span>                                                <span class="co">// #1</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span> <span class="op">{}</span>                                             <span class="co">// #2</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> S <span class="op">{</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+(</span>S, S<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> S <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span> <span class="co">// #3</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-(</span>S<span class="op">)</span> <span class="op">-&gt;</span> S <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span>                    <span class="co">// #4</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-(</span>S, S<span class="op">)</span> <span class="op">-&gt;</span> S <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span>                 <span class="co">// #5</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> f<span class="op">()</span> <span class="op">{}</span>                                              <span class="co">// #6</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span> <span class="op">{}</span>                                           <span class="co">// #7</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>  S<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{}</span>                                          <span class="co">// #8</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">~</span>S<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{}</span>                                         <span class="co">// #9</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-&gt;(</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> S<span class="op">*</span>;           <span class="co">// #10</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">[](</span><span class="kw">this</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span> self, <span class="dt">int</span> i<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span>;         <span class="co">// #11</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">auto</span> f<span class="op">(</span>S<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">int</span>;                                 <span class="co">// #12</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> fptr <span class="op">=</span> <span class="dt">void</span><span class="op">(*)(</span><span class="dt">long</span><span class="op">)</span>;</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span> fptr <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">&amp;</span>g; <span class="op">}</span>                  <span class="co">// #13</span></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>S <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;                    <span class="co">// #14</span></span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a>S f<span class="op">(</span><span class="dt">int</span>, <span class="dt">long</span><span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> S<span class="op">{}</span>; <span class="op">}</span>                             <span class="co">// #15</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> U <span class="op">:</span> S <span class="op">{}</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> h<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>  S s;</span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a>  U u;</span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>f<span class="op">())</span>;                     <span class="co">// ok, &amp;#1             (A)</span></span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;                    <span class="co">// ok, &amp;#2             (B)</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>f<span class="op">(</span>std<span class="op">::</span>declval<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;()))</span>;  <span class="co">// ok, &amp;#2             (C)</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">1</span><span class="bu">s</span><span class="op">))</span>;                   <span class="co">// ok, &amp;#2 (!)         (D)</span></span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s <span class="op">+</span> s<span class="op">)</span>;                   <span class="co">// ok, &amp;#3             (E)</span></span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(-</span>s<span class="op">)</span>;                      <span class="co">// ok, &amp;#4             (F)</span></span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(-</span>u<span class="op">)</span>;                      <span class="co">// ok, &amp;#4 (!)         (G)</span></span>
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s <span class="op">-</span> s<span class="op">)</span>;                   <span class="co">// ok, &amp;#5             (H)</span></span>
<span id="cb8-33"><a href="#cb8-33" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">.</span>f<span class="op">())</span>;                   <span class="co">// ok, &amp;#6             (I)</span></span>
<span id="cb8-34"><a href="#cb8-34" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>u<span class="op">.</span>f<span class="op">())</span>;                   <span class="co">// ok, &amp;#6 (!)         (J)</span></span>
<span id="cb8-35"><a href="#cb8-35" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">.</span>f<span class="op">(</span><span class="dv">2</span><span class="op">))</span>;                  <span class="co">// ok, &amp;#7             (K)</span></span>
<span id="cb8-36"><a href="#cb8-36" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">)</span>;                       <span class="co">// error, constructor  (L)</span></span>
<span id="cb8-37"><a href="#cb8-37" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">.</span>S<span class="op">::~</span>S<span class="op">())</span>;               <span class="co">// error, destructor   (M)</span></span>
<span id="cb8-38"><a href="#cb8-38" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">-&gt;</span>f<span class="op">())</span>;                  <span class="co">// ok, &amp;#6 (not &amp;#10)  (N)</span></span>
<span id="cb8-39"><a href="#cb8-39" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">.</span>S<span class="op">::</span><span class="kw">operator</span><span class="op">-&gt;())</span>;       <span class="co">// ok, &amp;#10            (O)</span></span>
<span id="cb8-40"><a href="#cb8-40" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">[</span><span class="dv">1</span><span class="op">])</span>;                    <span class="co">// ok, &amp;#11            (P)</span></span>
<span id="cb8-41"><a href="#cb8-41" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>S<span class="op">::</span>f<span class="op">(</span>S<span class="op">{}))</span>;               <span class="co">// ok, &amp;#12            (Q)</span></span>
<span id="cb8-42"><a href="#cb8-42" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">.</span>f<span class="op">(</span>S<span class="op">{}))</span>;                <span class="co">// ok, &amp;#12            (R)</span></span>
<span id="cb8-43"><a href="#cb8-43" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>s<span class="op">(</span><span class="dv">1</span><span class="bu">l</span><span class="op">))</span>;                   <span class="co">// error, #13          (S)</span></span>
<span id="cb8-44"><a href="#cb8-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>declcall<span class="op">(</span>s<span class="op">(</span><span class="dv">1</span><span class="bu">l</span><span class="op">)))&gt;(</span>s<span class="op">)</span>;   <span class="co">// ok, &amp;13   (S)</span></span>
<span id="cb8-45"><a href="#cb8-45" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>f<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">))</span>;                 <span class="co">// ok, &amp;#15            (T)</span></span>
<span id="cb8-46"><a href="#cb8-46" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span><span class="kw">new</span> <span class="op">(</span><span class="kw">nullptr</span><span class="op">)</span> S<span class="op">())</span>;       <span class="co">// error, not function (U)</span></span>
<span id="cb8-47"><a href="#cb8-47" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span><span class="kw">delete</span> <span class="op">&amp;</span>s<span class="op">)</span>;               <span class="co">// error, not function (V)</span></span>
<span id="cb8-48"><a href="#cb8-48" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span><span class="dv">1</span> <span class="op">+</span> <span class="dv">1</span><span class="op">)</span>;                   <span class="co">// error, built-in     (W)</span></span>
<span id="cb8-49"><a href="#cb8-49" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">([]{</span></span>
<span id="cb8-50"><a href="#cb8-50" aria-hidden="true" tabindex="-1"></a>       <span class="cf">return</span> declcall<span class="op">(</span>f<span class="op">())</span>;</span>
<span id="cb8-51"><a href="#cb8-51" aria-hidden="true" tabindex="-1"></a>    <span class="op">}()())</span>;                          <span class="co">// error (unevaluated) (X)</span></span>
<span id="cb8-52"><a href="#cb8-52" aria-hidden="true" tabindex="-1"></a>  declcall<span class="op">(</span>S<span class="op">{}</span> <span class="op">&lt;</span> S<span class="op">{})</span>;               <span class="co">// error, synthesized  (Y)</span></span>
<span id="cb8-53"><a href="#cb8-53" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.1" id="interesting-cases-in-the-above-example"><span class="header-section-number">4.1</span> Interesting cases in the above
example<a href="#interesting-cases-in-the-above-example" class="self-link"></a></h2>
<ul>
<li>resolving different members of a free-function overload set (A, B,
C, D, T)
<ul>
<li>the (D) case is important - the
<code class="sourceCode default">short</code> argument still resolves to
the <code class="sourceCode default">int</code> overload!</li>
</ul></li>
<li>resolving inline friend a.k.a. “hidden friend” (E)</li>
<li>constructors and destructors (L, M, U, V) - see the <strong>possible
extensions</strong> chapter.</li>
<li>resolving different member of a member-function overload set (I, J,
K, N, Q, R)
<ul>
<li>the (J) example is important - the call on
<code class="sourceCode default">u</code> still resolves to a member
function of <code class="sourceCode default">S</code>.</li>
</ul></li>
<li>resolving built-in non-functions (W): we could make this work in a
future extension (see that chapter).</li>
<li>resolving <code class="sourceCode default">operator-&gt;</code> (N
and O). (<span>7.6.1.1
<a href="https://wg21.link/expr.post.general">[expr.post.general]</a></span>)
specifies that
<code class="sourceCode default"><em>postfix-expression</em></code>s
group left-to-right, which means the top-most postfix-expression is the
call to <code class="sourceCode default">f()</code>, and not the
<code class="sourceCode default">-&gt;</code>. To get to
<code class="sourceCode default">S::operator-&gt;</code>, we have to ask
for it explicitly.</li>
<li>surrogate function call (S) - again, the top-most call-expression is
the function call to <code class="sourceCode default">g</code>, so the
type of <code class="sourceCode default">g</code> is returned, but it’s
not a constant expression. We can get it by evaluating the operand with
<code class="sourceCode default">static_cast</code>.</li>
<li>nested calls: (X) the top-level call is a call to a function-pointer
to #2, so that is what is returned, but since obtaining the value of the
function pointer requires evaluation, this is ill-formed. Getting the
type is fine.</li>
<li>Synthesized operators (Y) - these are not functions that we can take
pointers to, so unless we “force-manufacture” one, we can’t make this
work.</li>
</ul>
<h2 data-number="4.2" id="pointers-to-virtual-member-functions"><span class="header-section-number">4.2</span> Pointers to virtual member
functions<a href="#pointers-to-virtual-member-functions" class="self-link"></a></h2>
<p>This paper is effectively a counterpart to
<code class="sourceCode default">std::invoke</code> - give me a pointer
to the thing that would be invoked by this expression, so I can do it
later.</p>
<p>This poses a problem with pointers to virtual member functions
obtained via explicit access. Observe:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">virtual</span> B<span class="op">*</span> f<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D <span class="op">:</span> B <span class="op">{</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    D<span class="op">*</span> f<span class="op">()</span> <span class="kw">override</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    D d;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>    B<span class="op">&amp;</span> rb <span class="op">=</span> d; <span class="co">// d, but type is ref-to-B</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    d<span class="op">.</span>f<span class="op">()</span>;    <span class="co">// calls D::f</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    rb<span class="op">.</span>f<span class="op">()</span>;   <span class="co">// calls D::f</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>    d<span class="op">.</span>B<span class="op">::</span>f<span class="op">()</span>; <span class="co">// calls B::f</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> pf <span class="op">=</span> <span class="op">&amp;</span>B<span class="op">::</span>f;</span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span>d<span class="op">.*</span>pf<span class="op">)()</span>; <span class="co">// calls D::f (!)</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This begs the question: should there be a difference between these
three expressions?</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> b_f <span class="op">=</span> declcall<span class="op">(</span>d<span class="op">.</span>B<span class="op">::</span>f<span class="op">())</span>; <span class="co">// (1)</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> rb_f <span class="op">=</span> declcall<span class="op">(</span>rb<span class="op">.</span>f<span class="op">())</span>;  <span class="co">// (2)</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> d_f <span class="op">=</span> declcall<span class="op">(</span>d<span class="op">.</span>f<span class="op">())</span>;    <span class="co">// (3)</span></span></code></pre></div>
<p>Their types are not in question. (1) and (2) certainly should have
the same type ( <code class="sourceCode default">B* (B::*) ()</code> ),
while (3) has type (
<code class="sourceCode default">D* (D::*) ()</code>).</p>
<p>However, what about when we use them?</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">// (d, rb, b_f, rb_f, d_f as above)</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="op">(</span>d<span class="op">.*</span>rb_f<span class="op">)()</span>; <span class="co">// definitely calls D::f, same as rb.f()</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">(</span>d<span class="op">.*</span>d_f<span class="op">)()</span>;  <span class="co">// definitely calls D::f, same as d.f()</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="op">(</span>d<span class="op">.*</span>b_f<span class="op">)()</span>; <span class="co">// does it call B::f or D::f?</span></span></code></pre></div>
<p>It is the position of the author that
<code class="sourceCode default">(x.*declcall(x.Base::f()))()</code>
should call <code class="sourceCode default">Base::f</code>, because
<code class="sourceCode default">INVOKE</code> should be a perfect
complement to <code class="sourceCode default">declcall</code>.</p>
<p>However, this kind of pointer to member function currently does not
exist, although it’s trivially implementable (GCC has an extension: <a href="https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Bound-member-functions.html" class="uri">https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Bound-member-functions.html</a>).
The author proposes to add the “devirtualized member function
pointer”</p>
<p>Unlike the GCC extension, the type of the devirtualized member
function pointer is not distinguishable from the regular member function
pointer, to enable generic programming with the regular
pointer-to-member-function call syntax.</p>
<h3 data-number="4.2.1" id="pointers-to-pure-virtual-functions"><span class="header-section-number">4.2.1</span> Pointers to pure virtual
functions<a href="#pointers-to-pure-virtual-functions" class="self-link"></a></h3>
<p>Conciser the following:</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 class="kw">struct</span> ABC <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">virtual</span> <span class="dt">int</span> f<span class="op">()</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> h<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> x <span class="op">=</span> declcall<span class="op">(</span>declval<span class="op">&lt;</span>ABC<span class="op">&amp;&gt;().</span>f<span class="op">())</span>; <span class="co">// 1</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> y <span class="op">=</span> declcall<span class="op">(</span>declval<span class="op">&lt;</span>ABC<span class="op">&amp;&gt;().</span>ABC<span class="op">::</span>f<span class="op">())</span>; <span class="co">// 2</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>What is (1)? What is (2)? Should (2) be ill-formed? Return a regular
non-devirtualized pointer-to-member-function?</p>
<p>No. Unfortunately, pure virtual functions can actually be
defined;</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> ABC<span class="op">::</span>f<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">1</span>; <span class="op">}</span> <span class="co">// OK!</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">:</span> ABC <span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> f<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">2</span>; <span class="op">}</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    B b;</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    b<span class="op">.</span>f<span class="op">()</span>; <span class="co">// OK, 2</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>    b<span class="op">.</span>ABC<span class="op">::</span>f<span class="op">()</span>; <span class="co">// OK, 1</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>We propose that the following happens:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> h<span class="op">()</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    B b;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> x <span class="op">=</span> declcall<span class="op">(</span>declval<span class="op">&lt;</span>ABC<span class="op">&amp;&gt;().</span>f<span class="op">())</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> y <span class="op">=</span> declcall<span class="op">(</span>declval<span class="op">&lt;</span>ABC<span class="op">&amp;&gt;().</span>ABC<span class="op">::</span>f<span class="op">())</span>;</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span>b<span class="op">.*</span>x<span class="op">)()</span>; <span class="co">// OK, 2, does virtual dispatch</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span>b<span class="op">.*</span>y<span class="op">)()</span>; <span class="co">// OK, 1, does not do virtual dispatch</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="4.2.2" id="comparison-of-devirtualized-values-of-pointer-to-member-function-type"><span class="header-section-number">4.2.2</span> Comparison of devirtualized
values of pointer-to-member-function type<a href="#comparison-of-devirtualized-values-of-pointer-to-member-function-type" class="self-link"></a></h3>
<p>Comparison of values of pointer-to-member-function type where either
operand points to a <code class="sourceCode default">virtual</code>
function is unspecified in c++23 (<span>7.6.10
<a href="https://wg21.link/expr.eq">[expr.eq]</a></span>).</p>
<p>We have the ability to define it further.</p>
<p>Specifically, if both operands are devirtualized pointers to members,
the comparison should be performed under the current rules for pointers
to nonvirtual member functions; virtual and nonvirtual pointers to
member functions should compare unequal.</p>
<p>We could also define taking the address of member functions marked
<code class="sourceCode default">final</code> to yield devirtualized
pointers-to-member-functions, but that would be a separate paper.</p>
<p>EWG question: Is EWG interested in such a paper?</p>
<h2 data-number="4.3" id="alternatives-to-syntax"><span class="header-section-number">4.3</span> Alternatives to syntax<a href="#alternatives-to-syntax" class="self-link"></a></h2>
<p>We could wait for reflection in which case
<code class="sourceCode default">declcall</code> is implementable when
we have expression reflections.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>info r<span class="op">&gt;</span> <span class="kw">constexpr</span> <span class="kw">auto</span> declcall <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>is_nonstatic_member<span class="op">(</span>r<span class="op">))</span> <span class="op">{</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> pointer_to_member<span class="op">&lt;[:</span>pm_type_of<span class="op">(</span>r<span class="op">):]&gt;(</span>r<span class="op">)</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> entity_ref<span class="op">&lt;[:</span>type_of<span class="op">:]&gt;(</span>r<span class="op">)</span>;</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="co">/* insert additional cases as we define them. */</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}()</span>;</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>; <span class="co">//1 </span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span><span class="dt">long</span><span class="op">)</span>; <span class="co">//2</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> fptr_1 <span class="op">=</span> <span class="op">[:</span> declcall<span class="op">&lt;^</span>f<span class="op">(</span><span class="dv">1</span><span class="op">)&gt;</span> <span class="op">:]</span>; <span class="co">// 1</span></span></code></pre></div>
<p>It’s unlikely to be quite as efficient as just hooking directly into
the resolver, but it does have the nice property that it doesn’t take up
a whole keyword.</p>
<p>It <em>also</em> currently only works for constant expressions, so
it’s not general-purpose. For general arguments, one would need to pass
reflections of arguments, and if those aren’t constant expressions, this
gets really complicated.
<code class="sourceCode default">declcall</code> is far simpler.</p>
<p>Many thanks to Daveed Vandevoorde for helping out with this
example.</p>
<h2 data-number="4.4" id="naming"><span class="header-section-number">4.4</span> Naming<a href="#naming" class="self-link"></a></h2>
<p>I think <code class="sourceCode default">declcall</code> is a
reasonable name - it hints that it’s an unevaluated operand, and it’s
how I implemented it in clang. EWG voted for it as well.</p>
<p><a href="https://codesearch.isocpp.org/cgi-bin/cgi_ppsearch?q=declcall&amp;search=Search">codesearch
for declcall</a> comes up with zero hits.</p>
<p>For all intents and purposes, this facility grammatically behaves in
the same way as <code class="sourceCode default">sizeof</code>, except
that we should require the parentheses around the operand.</p>
<p>We could call it something other unlikely to conflict, but I like
<code class="sourceCode default">declcall</code></p>
<ul>
<li><code class="sourceCode default">declcall</code></li>
<li><code class="sourceCode default">declinvoke</code></li>
<li><code class="sourceCode default">calltarget</code></li>
<li><code class="sourceCode default">expression_targetof</code></li>
<li><code class="sourceCode default">calltargetof</code></li>
<li><code class="sourceCode default">decltargetof</code></li>
<li><code class="sourceCode default">resolvetarget</code></li>
</ul>
<p><code class="sourceCode default">declcall</code> can be thought of as
“resolve this call expression to the declaration of the called
entity”.</p>
<h1 data-number="5" id="implementation-experience"><span class="header-section-number">5</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>Hana Dusíková implemented the proposal in a clang fork along with
some other extensions, an example of which can be found here:
https://compiler-explorer.com/z/71T6GoeMo.</p>
<p>The implementation took her approximately 2 afternoons. The proposal
was implemented for the constexpr evaluator, and has an additional
capability where base expressions that are constant expressions are not
ill-formed, but instead return that constant, getting around the
requirement for <code class="sourceCode default">static_cast</code>.</p>
<p>There were no issues with the implementation of devirtualized
function pointers, at least on the Itanium ABI (they are already part of
the ABI). Microsoft’s ABI readily admits an implementation as well, and
we have confirmation of this from Microsoft.</p>
<h1 data-number="6" id="usecases"><span class="header-section-number">6</span> Usecases<a href="#usecases" class="self-link"></a></h1>
<p>Broadly, anywhere where we want to type-erase a call-expression.
Broad uses in any type-erasure library, smart pointers, ABI-stable
interfaces, compilation barriers, task-queues, runtime lifts for
double-dispatch, and the list goes on and on and on and …</p>
<h2 data-number="6.1" id="what-does-this-give-us-that-we-dont-have-yet"><span class="header-section-number">6.1</span> What does this give us that we
don’t have yet<a href="#what-does-this-give-us-that-we-dont-have-yet" class="self-link"></a></h2>
<h3 data-number="6.1.1" id="resolving-overload-sets-for-callbacks-without-lambdas"><span class="header-section-number">6.1.1</span> Resolving overload sets for
callbacks without lambdas<a href="#resolving-overload-sets-for-callbacks-without-lambdas" class="self-link"></a></h3>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co">// generic context</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>sort<span class="op">(</span>v<span class="op">.</span>begin<span class="op">()</span>, v<span class="op">.</span>end<span class="op">()</span>, <span class="op">[](</span><span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> x, <span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> my_comparator<span class="op">(</span>x, y<span class="op">)</span>; <span class="co">// some overload set</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">})</span>;</span></code></pre></div>
<p>becomes</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">// look ma, no lambda, no inlining, and less code generation!</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>sort<span class="op">(</span>v<span class="op">.</span>begin<span class="op">()</span>, v<span class="op">.</span>end<span class="op">()</span>, declcall<span class="op">(</span>my_comparator<span class="op">(</span>v<span class="op">.</span>front<span class="op">()</span>, v<span class="op">.</span>front<span class="op">()))</span>;</span></code></pre></div>
<p>Note also, that in the case of a
<code class="sourceCode default">vector&lt;int&gt;</code>, the ABI for
the comparator is likely to take those by value, which means we get a
better calling convention.</p>
<p><code class="sourceCode default">static_cast&lt;bool(*)(int, int)&gt;(my_comparator)</code>
is not good enough here - the resolved comparator could take
<code class="sourceCode default">long</code>s, for instance.</p>
<h3 data-number="6.1.2" id="copy-elision-in-callbacks"><span class="header-section-number">6.1.2</span> Copy-elision in callbacks<a href="#copy-elision-in-callbacks" class="self-link"></a></h3>
<p>We cannot correctly forward immovable type construction through
forwarding function.</p>
<p>Example:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> f<span class="op">(</span>nonmovable<span class="op">)</span> <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#if __cpp_expression_aliases &lt; 202506</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// doesn&#39;t work</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> obj<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> f<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>obj<span class="op">)&gt;(</span>obj<span class="op">))</span>; <span class="co">// 1</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#else</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>    <span class="co">// would work if we also had expression aliases</span></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> obj<span class="op">)</span> </span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>       <span class="op">=</span> declcall<span class="op">(</span>f<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>obj<span class="op">&gt;(</span>obj<span class="op">)))</span>;      <span class="co">// 2</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#endif</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> some_customization_point_object;</span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> continue_with_result<span class="op">(</span><span class="kw">auto</span> callback<span class="op">)</span> <span class="op">{</span></span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>    callback<span class="op">(</span>nonmovable<span class="op">{</span>read_something<span class="op">()})</span>;</span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> handler<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a>    continue_with_result<span class="op">(</span>declcall<span class="op">(</span>f<span class="op">(</span>nonmovable<span class="op">{})))</span>; <span class="co">// works</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a>    <span class="co">// (1) doesn&#39;t work, (2) works</span></span>
<span id="cb18-23"><a href="#cb18-23" aria-hidden="true" tabindex="-1"></a>    continue_with_result<span class="op">(</span>some_customization_point_object<span class="op">)</span>;</span>
<span id="cb18-24"><a href="#cb18-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="6.1.3" id="taking-the-address-of-a-hidden-friend-function"><span class="header-section-number">6.1.3</span> Taking the address of a
hidden friend function<a href="#taking-the-address-of-a-hidden-friend-function" class="self-link"></a></h3>
<p>The language has currently no mechanism to take a pointer to a
“hidden friend” function.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> S <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">inline</span> <span class="kw">friend</span> <span class="dt">int</span> foo<span class="op">(</span>S, <span class="dt">int</span> a<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> a; <span class="op">}</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">int</span><span class="op">(*</span>foo_ptr<span class="op">)(</span>S, <span class="dt">int</span><span class="op">)</span> <span class="op">=</span> <span class="op">&amp;</span>S<span class="op">::</span>foo; <span class="co">// error, no S::foo</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>declcall<span class="op">(</span>foo<span class="op">(</span>S<span class="op">{}</span>, <span class="dv">1</span><span class="op">))</span>; <span class="co">// ok, S::foo.</span></span></code></pre></div>
<h3 data-number="6.1.4" id="no-way-to-skip-virtual-dispatch-when-calling-through-pointer-to-member-function"><span class="header-section-number">6.1.4</span> No way to skip virtual
dispatch when calling through pointer-to-member-function<a href="#no-way-to-skip-virtual-dispatch-when-calling-through-pointer-to-member-function" class="self-link"></a></h3>
<p>There is also no tool skip the virtual dispatch of a pointer to
virtual member function (later in the paper called “devirtualized
pointer”).</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">virtual</span> <span class="dt">char</span> f<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> <span class="ch">&#39;B&#39;</span>; <span class="op">}</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D <span class="op">:</span> B <span class="op">{</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> f<span class="op">()</span> <span class="kw">override</span> <span class="op">{</span> <span class="cf">return</span> <span class="ch">&#39;D&#39;</span>; <span class="op">}</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>If we have an object of type
<code class="sourceCode default">D</code>, we can still explicity invoke
<code class="sourceCode default">B::f</code>, but there is no way to do
that via a pointer-to-member-function in C++23.</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>D x;</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>x<span class="op">.</span>B<span class="op">::</span>f<span class="op">()</span>; <span class="co">// &#39;B&#39;</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>x<span class="op">.</span>f<span class="op">()</span>;    <span class="co">// &#39;D&#39;</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>x<span class="op">.*(&amp;</span>B<span class="op">::</span>f<span class="op">)()</span>;  <span class="co">// &#39;D&#39; (!)</span></span></code></pre></div>
<h2 data-number="6.2" id="thats-not-good-enough-to-do-all-that-work.-what-else"><span class="header-section-number">6.2</span> That’s not good enough to do
all that work. What else?<a href="#thats-not-good-enough-to-do-all-that-work.-what-else" class="self-link"></a></h2>
<p>Together with <span class="citation" data-cites="P2826R0">[<a href="#ref-P2826R0" role="doc-biblioref">P2826R0</a>]</span>, the two
papers constitute the ability to implement
<em>expression-equivalent</em> in many important cases (not all, that’s
probably impossible).</p>
<p><span class="citation" data-cites="P2826R0">[<a href="#ref-P2826R0" role="doc-biblioref">P2826R0</a>]</span> proposes a way for a function
signature to participate in overload resolution and, if it wins, be
replaced by some other function.</p>
<p>This facility is the key to <em>finding</em> that other function. The
ability to preserve prvalue-ness is crucial to implementing quite a lot
of the standard library customization points as mandated by the
standard, without compiler help.</p>
<h1 data-number="7" id="guidance-given"><span class="header-section-number">7</span> Guidance Given:<a href="#guidance-given" class="self-link"></a></h1>
<h2 data-number="7.1" id="reflection-1"><span class="header-section-number">7.1</span> Reflection?<a href="#reflection-1" class="self-link"></a></h2>
<p><strong>Do we want to punt the syntax to reflection, or is this basic
enough to warrant this feature? (Knowing that reflection will need more
work from the user to get the pointer value).</strong></p>
<p>SG7 said no, this is good. So has EWG.</p>
<h2 data-number="7.2" id="unevaluated-operands-only"><span class="header-section-number">7.2</span> Unevaluated operands only?<a href="#unevaluated-operands-only" class="self-link"></a></h2>
<p><strong>Do we care that it only works on unevaluated operands? (With
the <code class="sourceCode default">static_cast</code> fallback in
run-time cases)</strong></p>
<p>SG7 confirmed author’s position that this is the correct design, and
so has EWG.</p>
<h1 data-number="8" id="proposed-wording"><span class="header-section-number">8</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<p>In the table of keywords, in <span>5.12
<a href="https://wg21.link/lex.key">[lex.key]</a></span>, add</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<div class="line-block"><code class="sourceCode default">declcall</code></div>
</blockquote>
</blockquote>

</div>
<p>In <span>6.3
<a href="https://wg21.link/basic.def.odr">[basic.def.odr]</a></span>,
clarify that <code class="sourceCode default">declcall</code> also
“names” functions in the same way that taking their address does.</p>
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> A
function is named by an expression or conversion if</p>
<ul>
<li>it is the selected member of an overload set (<span>6.5
<a href="https://wg21.link/basic.lookup">[basic.lookup]</a></span>,
<span>12.2
<a href="https://wg21.link/over.match">[over.match]</a></span>,
<span>12.3
<a href="https://wg21.link/over.over">[over.over]</a></span>) in an
overload resolution performed as part of forming that expression or
conversion, unless it is a pure virtual function and either the
expression is not an <em>id-expression</em> naming the function with an
explicitly qualified name or the expression forms a pointer to member
(<span>7.6.2.2
<a href="https://wg21.link/expr.unary.op">[expr.unary.op]</a></span>)<span class="rm" style="color: #bf0303"><del>.</del></span><span class="add" style="color: #006e28"><ins>; or</ins></span></li>
<li><span class="add" style="color: #006e28"><ins>it is the result of a
<span><code class="sourceCode default">declcall</code></span>
expression, unless the result is a pointer-to-member-function that is
not devirtualized.</ins></span></li>
</ul>
<p>[Note 2: This covers taking the address of functions (<span>7.3.4
<a href="https://wg21.link/conv.func">[conv.func]</a></span>,
<span>7.6.2.2
<a href="https://wg21.link/expr.unary.op">[expr.unary.op]</a></span>,
<span class="add" style="color: #006e28"><ins>[expr.declcall]</ins></span>), calls to
named functions (<span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>), operator
overloading (<span>12
<a href="https://wg21.link/over">[over]</a></span>), user-defined
conversions (<span>11.4.8.3
<a href="https://wg21.link/class.conv.fct">[class.conv.fct]</a></span>),
allocation functions for new-expressions (<span>7.6.2.8
<a href="https://wg21.link/expr.new">[expr.new]</a></span>), as well as
non-default initialization (<span>9.4
<a href="https://wg21.link/dcl.init">[dcl.init]</a></span>). A
constructor selected to copy or move an object of class type is
considered to be named by an expression or conversion even if the call
is actually elided by the implementation (<span>11.9.6
<a href="https://wg21.link/class.copy.elision">[class.copy.elision]</a></span>).
— end note]</p>
</blockquote>
</blockquote>
<p>In <span>7.6.2.1
<a href="https://wg21.link/expr.unary.general">[expr.unary.general]</a></span></p>
<blockquote>
<div class="line-block">    <em>unary-expression</em>:<br />
        …<br />
        <code class="sourceCode default">alignof ( <em>type-id</em> )</code><br />
        <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">declcall ( <em>expression</em> )</code></span></ins></span></div>
</blockquote>
<p>In <span>7.6.10
<a href="https://wg21.link/expr.eq">[expr.eq]</a></span>, edit paragraph
4.3</p>
<blockquote>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> If
either is a pointer to a virtual member function <span class="add" style="color: #006e28"><ins>and not devirtualized</ins></span>, the
result is unspecified. <span class="add" style="color: #006e28"><ins>[Note: If both are devirtualized, they are
treated as pointers to non-virtual member functions for the remainder of
this paragraph. – end note]</ins></span></li>
</ul>
</blockquote>
</blockquote>
<p><strong>ALTERNATIVE for EWG:</strong> should we also force unequal
comparison of devirtualized to nondevirtualized pointer values? In that
case, replace:</p>
<div class="rm" style="color: #bf0303">

<blockquote>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> If
either is a pointer to a virtual member function, the result is
unspecified.</li>
</ul>
</blockquote>
</blockquote>

</div>
<p>with</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> If
either is a pointer to a virtual member function, then if exactly one of
them is devirtualized, they compare unequal. If neither is
devirtualized, the result is unspecified. <span class="add" style="color: #006e28"><ins>[Note: If both are devirtualized, they are
treated as pointers to non-virtual member functions for the remainder of
this paragraph. – end note]</ins></span></li>
</ul>
</blockquote>
</blockquote>

</div>
<p><strong>END ALTERNATIVE</strong>.</p>
<p>In <span>9.3.4.4
<a href="https://wg21.link/dcl.mptr">[dcl.mptr]</a></span>, insert a new
paragraph 5 after p4, and renumber section:</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The value of a pointer to member function can be <em>devirtualized</em>.
[Note: Devirtualized pointers to member functions may be formed by
<code class="sourceCode default">declcall</code> ([expr.declcall]), and
call expressions involving them call the function they point to, and not
the final overrider (<span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>/2,
<span>11.7.3
<a href="https://wg21.link/class.virtual">[class.virtual]</a></span>). –
end note]</p>
</blockquote>
</blockquote>

</div>
<p>In <span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>, change
p2:</p>
<blockquote>
<blockquote>
<p>If the selected function is non-virtual, or if the
<em>id-expression</em> in the class member access expression is a
<em>qualified-id</em> <span class="add" style="color: #006e28"><ins>, or
the bound function prvalue (<span>7.6.4
<a href="https://wg21.link/expr.mptr.oper">[expr.mptr.oper]</a></span>)
is obtained from a devirtualized pointer (<span>9.3.4.4
<a href="https://wg21.link/dcl.mptr">[dcl.mptr]</a></span>)</ins></span>,
that function is called. Otherwise, its final overrider in the dynamic
type of the object expression is called; such a call is referred to as a
virtual function call.</p>
</blockquote>
</blockquote>
<p>Add new section under <span>7.6.2.6
<a href="https://wg21.link/expr.alignof">[expr.alignof]</a></span>, with
a stable tag of <span class="add" style="color: #006e28"><ins>[expr.declcall]</ins></span>.</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
When evaluated, the <code class="sourceCode default">declcall</code>
operator yields a pointer or pointer to member to the function or member
function which would be invoked by its expression. The result is a
prvalue. The operand of declcall is an unevaluated operand. [Note: It
can be said that, when evaluated,
<code class="sourceCode default">declcall</code> resolves the call to a
specific declaration. –end note]</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
If the <em>expression</em> is transformed into an equivalent function
call (<span>12.2.2.3
<a href="https://wg21.link/over.match.oper">[over.match.oper]</a></span>),
replace <em>expression</em> by the transformed expression for the
remainder of this subclause.
<!-- make this cover the surrogate call function case too --> If the
<em>expression</em> is not a (possibly transformed) function call
expression (<span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>), the
program is ill-formed. Such a (possibly transformed) <em>expression</em>
is of the form <em>postfix-expression</em> (
<em>expression-list<sub>opt</sub></em> ).
<!-- Jens says built-in operators aren't function calls and thus get taken out here. --></p>
</blockquote>
</blockquote>
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
If the <em>postfix-expression</em> is of the (possibly transformed) form
<code class="sourceCode default">E1 .* E2</code> (<span>7.6.4
<a href="https://wg21.link/expr.mptr.oper">[expr.mptr.oper]</a></span>)
where <code class="sourceCode default">E2</code> is a
<em>cast-expression</em> of type
<code class="sourceCode default">T</code>, then the result has type
<code class="sourceCode default">T</code> and the
<code class="sourceCode default">declcall</code> expression shall not be
potentially-evaluated.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Otherwise, if the <em>postfix-expression</em> is neither a qualified nor
an unqualified function call (<span>12.2.2.2.2
<a href="https://wg21.link/over.call.func">[over.call.func]</a></span>),
then: where <code class="sourceCode default">T</code> is the type of the
<em>postfix-expression</em>, if
<code class="sourceCode default">T</code> is a pointer-to-function type,
the result has type <code class="sourceCode default">T</code>, and
“pointer to <code class="sourceCode default">T</code>” otherwise.</p>
</blockquote>
</blockquote>
<!--
If the _postfix-expression_ is a prvalue of pointer type `T`,
  then the result has type `T`
  and the `declcall` expression shall not be potentially-evaluated.
-->
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Otherwise, let <em>F</em> be the function selected by overload
resolution (<span>12.2.2.2
<a href="https://wg21.link/over.match.call">[over.match.call]</a></span>),
and <code class="sourceCode default">T</code> its type.</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> If
<em>F</em> is a constructor, destructor, or synthesized candidate
(<span>7.6.9
<a href="https://wg21.link/expr.rel">[expr.rel]</a></span>, <span>7.6.10
<a href="https://wg21.link/expr.eq">[expr.eq]</a></span>), the program
is ill-formed.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
Otherwise, if <em>F</em> is an implicit object member function declared
as a member of class <code class="sourceCode default">C</code>, the
<em>postfix-expression</em> is a class member access expression
(<span>7.6.1.5
<a href="https://wg21.link/expr.ref">[expr.ref]</a></span>). The result
has type “pointer to member of class
<code class="sourceCode default">C</code> of type
<code class="sourceCode default">T</code>” and points to <em>F</em>. If
the <em>id-expression</em> in the class member access expression of this
call is a <em>qualified-id</em>, the result pointer is a
<em>devirtualized pointer</em>. (<span>6.8.4
<a href="https://wg21.link/basic.compound">[basic.compound]</a></span>).</p>
<p>[Example:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>  struct B { virtual B* f() { return this; } };</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  struct D : B { D* f() override { return this; } };</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>  struct D2 : B {};</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  void g() {</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>     D d;</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>     B&amp; rb = d;</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>     auto b_f = declcall(d.B::f()); // type: B* (B::*)() </span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>     auto rb_f = declcall(rb.f());  // type: B* (B::*)()</span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>     auto d_f = declcall(d.f());    // type: D* (D::*)()</span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>     declcall(D2().f());            // type: B* (B::*)()</span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a>     (d.*b_f)();  // B::f, devirtualized</span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>     (d.*rb_f)(); // D::f, via virtual dispatch</span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>     (d.*d_f)();  // D::f, via virtual dispatch</span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
<p>– end example]</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.4)</a></span>
Otherwise, the result has type “pointer to
<code class="sourceCode default">T</code>” and points to
<em>F</em>.</p></li>
</ul>
</blockquote>
</blockquote>

</div>
<p>In <span>11.7.4
<a href="https://wg21.link/class.abstract">[class.abstract]</a></span>,
turn the text about when a pure virtual function need be defined into a
note, and fill out the note:</p>
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
A virtual function is specified as a <em>pure virtual function</em> by
using a <em>pure-specifier</em> (<span>11.4
<a href="https://wg21.link/class.mem">[class.mem]</a></span>) in the
function declaration in the class definition.</p>
<p>[Note 2: Such a function might be inherited: see below. — end
note]</p>
<p>A class is an abstract class if it has at least one pure virtual
function.</p>
<p>[Note 3: An abstract class can be used only as a base class of some
other class; no objects of an abstract class can be created except as
subobjects of a class derived from it (<span>6.2
<a href="https://wg21.link/basic.def">[basic.def]</a></span>, <span>11.4
<a href="https://wg21.link/class.mem">[class.mem]</a></span>). -— end
note]</p>
<p><span class="add" style="color: #006e28"><ins>[Note 4:</ins></span> A
pure virtual function need be defined only if called with, or as if with
(<span>11.4.7
<a href="https://wg21.link/class.dtor">[class.dtor]</a></span>), the
qualified-id syntax (<span>7.5.5.3
<a href="https://wg21.link/expr.prim.id.qual">[expr.prim.id.qual]</a></span>).
<span class="add" style="color: #006e28"><ins>A devirtualized pointer to
member function is always obtained from such an expression within a
<span><code class="sourceCode default">declcall</code></span> expression
(<span>9.3.4.4
<a href="https://wg21.link/dcl.mptr">[dcl.mptr]</a></span>) –end
note]</ins></span>.</p>
</blockquote>
</blockquote>
<p>In <span>13.6
<a href="https://wg21.link/temp.type">[temp.type]</a></span> add:</p>
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Two values are template-argument-equivalent if they are of the same type
and</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> they
are of integral type and their values are the same, or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> they
are of floating-point type and their values are identical, or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> they
are of type <code class="sourceCode default">std::nullptr_t</code>,
or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span> they
are of enumeration type and their values are the same,113 or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span> they
are of pointer type and they have the same pointer value, or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.6)</a></span> they
are of pointer-to-member type and they refer to the same class member
<span class="add" style="color: #006e28"><ins>and they are either both
devirtualized or both not devirtualized,</ins></span> or are both the
null member pointer value, or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.7)</a></span> they
are of reference type and they refer to the same object or function,
or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.8)</a></span> they
are of array type and their corresponding elements are
template-argument-equivalent,114 or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.9)</a></span> they
are of union type and either they both have no active member or they
have the same active member and their active members are
template-argument-equivalent, or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.10)</a></span>
they are of a closure type (<span>7.5.6.2
<a href="https://wg21.link/expr.prim.lambda.closure">[expr.prim.lambda.closure]</a></span>),
or</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.11)</a></span>
they are of class type and their corresponding direct subobjects and
reference members are template-argument-equivalent.</li>
</ul>
</blockquote>
</blockquote>
<!--
FIXME (done): from Hubert: [expr.eq]/4 needs fixing (but see temp.type also
https://eel.is/c++draft/temp.type#2.1)
- fix comparison of pointers to member function:
- final -> same as devirtualized
- virtual/nonvirtual => unequal
- nonvirtual: can define comparison
- virtual-virtual: define as points to same member (will have identical results of overload resolution)

temp.type: pointers are either both devirtualized or both non-devirtualized
-->
<p>Into the list in (<span>13.8.3.4
<a href="https://wg21.link/temp.dep.constexpr">[temp.dep.constexpr]</a></span>)
paragraph 2.6, add <code class="sourceCode default">declcall</code>
alongside <code class="sourceCode default">alignof</code>, to ensure
that the <code class="sourceCode default">declcall</code> expression is
value-dependent only if it is type-dependent (and thus not
value-dependent if all the type information in the expression is
known).</p>
<blockquote>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
An <em>id-expression</em> is value-dependent if</p>
<ul>
<li>…</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.6)</a></span> it
names a potentially-constant variable (<span>7.7
<a href="https://wg21.link/expr.const">[expr.const]</a></span>) that is
initialized with an expression that is value-dependent.</li>
</ul>
<p>Expressions of the following form are value-dependent if the
<em>unary-expression</em> or <em>expression</em> is type-dependent or
the <em>type-id</em> is dependent:</p>
<div class="line-block">    <code class="sourceCode default">sizeof</code>
<em>unary-expression</em><br />
    <code class="sourceCode default">sizeof</code> ( <em>type-id</em>
)<br />
    <code class="sourceCode default">typeid</code> ( <em>expression</em>
)<br />
    <code class="sourceCode default">typeid</code> ( <em>type-id</em>
)<br />
    <code class="sourceCode default">alignof</code> ( <em>type-id</em>
)<br />
    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">declcall ( <em>expression</em> )</code></span></ins></span></div>
<p>[Note 1: For the standard library macro offsetof, see
[support.types]. -— end note]</p>
</blockquote>
</blockquote>
<p>Add feature-test macro into <span>17.3.2
<a href="https://wg21.link/version.syn">[version.syn]</a></span> in
section 2</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<div class="sourceCode" id="cb23"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>#define __cpp_declcall 2025XXL</span></code></pre></div>
</blockquote>
</blockquote>

</div>
<p>Add to Annex C:</p>
<div class="add" style="color: #006e28">

<blockquote>
<blockquote>
<div class="line-block"><strong>Affected subclause:</strong> <span>5.12
<a href="https://wg21.link/lex.key">[lex.key]</a></span><br />
<strong>Change:</strong> New keyword.</div>
<p><strong>Rationale:</strong> Required for new features.</p>
<p><strong>Effect on original feature:</strong> Added to Table 5, the
following identifier is now a new keyword: <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">declcall</code></span></ins></span>.
Valid C++ 2023 code using these identifiers is invalid in this revision
of C++.</p>
</blockquote>
</blockquote>

</div>
<h1 data-number="9" id="acknowledgements"><span class="header-section-number">9</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<ul>
<li>Alex Kremer for reviews,</li>
<li>Daveed Vandevoorde for many design discussions and implementation
guidance</li>
<li>For core language review, changes, and suggestions (alphabetized):
Barry Revzin, Brian Bi, Christof Meerwald, Davis Herring, Hubert Tong,
Jens Maurer, Joshua Berne, and Roger Orr.</li>
</ul>
<h1 data-number="10" id="bibliography"><span class="header-section-number">10</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-N4856" class="csl-entry" role="doc-biblioentry">
[N4856] David Sankel. 2020-03-02. C++ Extensions for Reflection. <a href="https://wg21.link/n4856"><div class="csl-block">https://wg21.link/n4856</div></a>
</div>
<div id="ref-P1240R1" class="csl-entry" role="doc-biblioentry">
[P1240R1] Daveed Vandevoorde, Wyatt Childers, Andrew Sutton, Faisal
Vali, Daveed Vandevoorde. 2019-10-08. Scalable Reflection in C++. <a href="https://wg21.link/p1240r1"><div class="csl-block">https://wg21.link/p1240r1</div></a>
</div>
<div id="ref-P2087R0" class="csl-entry" role="doc-biblioentry">
[P2087R0] Mihail Naydenov. 2020-01-12. Reflection Naming: fix reflexpr.
<a href="https://wg21.link/p2087r0"><div class="csl-block">https://wg21.link/p2087r0</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-P2300R6" class="csl-entry" role="doc-biblioentry">
[P2300R6] Michał Dominiak, Georgy Evtushenko, Lewis Baker, Lucian Radu
Teodorescu, Lee Howes, Kirk Shoop, Michael Garland, Eric Niebler, Bryce
Adelstein Lelbach. 2023-01-19. `std::execution`. <a href="https://wg21.link/p2300r6"><div class="csl-block">https://wg21.link/p2300r6</div></a>
</div>
<div id="ref-P2320R0" class="csl-entry" role="doc-biblioentry">
[P2320R0] Andrew Sutton, Wyatt Childers, Daveed Vandevoorde. 2021-02-15.
The Syntax of Static Reflection. <a href="https://wg21.link/p2320r0"><div class="csl-block">https://wg21.link/p2320r0</div></a>
</div>
<div id="ref-P2826R0" class="csl-entry" role="doc-biblioentry">
[P2826R0] Gašper Ažman. Replacement functions. <a href="https://wg21.link/P2826R0"><div class="csl-block">https://wg21.link/P2826R0</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
