<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-12-16" />
  <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>P2825R3</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-12-16</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>
    </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="#motivation-and-prior-art" id="toc-motivation-and-prior-art"><span class="toc-section-number">2</span> Motivation and Prior
Art<span></span></a>
<ul>
<li><a href="#related-work" id="toc-related-work"><span class="toc-section-number">2.1</span> Related Work<span></span></a></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">3</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">3.1</span> Interesting cases in the above
example<span></span></a></li>
<li><a href="#design-question-about-pointers-to-virtual-member-functions" id="toc-design-question-about-pointers-to-virtual-member-functions"><span class="toc-section-number">3.2</span> Design question about 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">3.3</span> Alternatives to
syntax<span></span></a></li>
<li><a href="#naming" id="toc-naming"><span class="toc-section-number">3.4</span> Naming<span></span></a></li>
</ul></li>
<li><a href="#usecases" id="toc-usecases"><span class="toc-section-number">4</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">4.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">4.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">5</span> Guidance Given:<span></span></a>
<ul>
<li><a href="#reflection-1" id="toc-reflection-1"><span class="toc-section-number">5.1</span> Reflection?<span></span></a></li>
<li><a href="#unevaluated-operands-only" id="toc-unevaluated-operands-only"><span class="toc-section-number">5.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">6</span> Proposed
Wording<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">7</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">8</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="motivation-and-prior-art"><span class="header-section-number">2</span> Motivation and Prior Art<a href="#motivation-and-prior-art" class="self-link"></a></h1>
<p>The language already has a number of sort-of overload resolution
facilities:</p>
<ul>
<li><code class="sourceCode default">static_cast</code></li>
<li>assignment to a variable of a given function pointer type</li>
<li>function calls (implicit) - the only one that actually works</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.</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> 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>
</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 the pointer to it</em>.</p>
<p>This is what this paper is trying to provide.</p>
<h2 data-number="2.1" id="related-work"><span class="header-section-number">2.1</span> Related Work<a href="#related-work" class="self-link"></a></h2>
<h3 data-number="2.1.1" id="reflection"><span class="header-section-number">2.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="2.1.2" id="library-fundamentals-ts-v3"><span class="header-section-number">2.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="3" id="proposal"><span class="header-section-number">3</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 an addressable function (such as a constructor,
destructor, built-in, etc.).</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>The expression is not a constant expression if the
<code class="sourceCode default"><em>expression</em></code> does not
resolve for unevaluated operands, such as with function pointer values
and surrogate functions.</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>
<p>TODO: call out difference between
<code class="sourceCode default">declcall(obj.f())</code> and
<code class="sourceCode default">declcall(obj.Base::f())</code> for
virtual f.</p>
<h2 data-number="3.1" id="interesting-cases-in-the-above-example"><span class="header-section-number">3.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>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 class="marginalizedparent"><a class="marginalized">(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="3.2" id="design-question-about-pointers-to-virtual-member-functions"><span class="header-section-number">3.2</span> Design question about pointers
to virtual member functions<a href="#design-question-about-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 calld 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
INVOKE should be a perfect inverse.</p>
<p>However, this kind of pointer to member function currently does not
exist, although it’s trivially implementable. Its type would not be
distinguishable from the current kind.</p>
<p>EWG should vote on this.</p>
<h2 data-number="3.3" id="alternatives-to-syntax"><span class="header-section-number">3.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="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">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-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="cb12-3"><a href="#cb12-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="cb12-4"><a href="#cb12-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="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-6"><a href="#cb12-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="cb12-7"><a href="#cb12-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="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}()</span>;</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-11"><a href="#cb12-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="cb12-12"><a href="#cb12-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="cb12-13"><a href="#cb12-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="3.4" id="naming"><span class="header-section-number">3.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.</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>
<h1 data-number="4" id="usecases"><span class="header-section-number">4</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="4.1" id="what-does-this-give-us-that-we-dont-have-yet"><span class="header-section-number">4.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="4.1.1" id="resolving-overload-sets-for-callbacks-without-lambdas"><span class="header-section-number">4.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="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="co">// generic context</span></span>
<span id="cb13-2"><a href="#cb13-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="cb13-3"><a href="#cb13-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="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="op">})</span>;</span></code></pre></div>
<p>becomes</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="co">// look ma, no lambda, no inlining, and less code generation!</span></span>
<span id="cb14-2"><a href="#cb14-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="4.1.2" id="copy-elision-in-callbacks"><span class="header-section-number">4.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="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="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="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#if __cpp_expression_aliases &lt; 202506</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// doesn&#39;t work</span></span>
<span id="cb15-5"><a href="#cb15-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="cb15-6"><a href="#cb15-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="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#else</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>    <span class="co">// would work if we also had expression aliases</span></span>
<span id="cb15-10"><a href="#cb15-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="cb15-11"><a href="#cb15-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="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>    <span class="pp">#endif</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> some_customization_point_object;</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-16"><a href="#cb15-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="cb15-17"><a href="#cb15-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="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> handler<span class="op">()</span> <span class="op">{</span></span>
<span id="cb15-21"><a href="#cb15-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="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>    <span class="co">// (1) doesn&#39;t work, (2) works</span></span>
<span id="cb15-23"><a href="#cb15-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="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="4.2" id="thats-not-good-enough-to-do-all-that-work.-what-else"><span class="header-section-number">4.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="5" id="guidance-given"><span class="header-section-number">5</span> Guidance Given:<a href="#guidance-given" class="self-link"></a></h1>
<h2 data-number="5.1" id="reflection-1"><span class="header-section-number">5.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="5.2" id="unevaluated-operands-only"><span class="header-section-number">5.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="6" id="proposed-wording"><span class="header-section-number">6</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<p>We base the approach on <span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>, which
distinguishes calls to lvalues that refer to functions, and prvalues of
function pointer type. We must then also handle operators which resolve
to a call to a function.</p>
<p>In the table of keywords, in [lex.key], add</p>
<p><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">declcall</code></span></ins></span></p>
<p>In <span>7.6.2.1
<a href="https://wg21.link/expr.unary.general">[expr.unary.general]</a></span></p>
<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>
<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 [expr.declcall].</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code class="sourceCode default">declcall</code> operator yields a
pointer to the function or member function which would be invoked by its
<em>expression</em>. The operand of
<code class="sourceCode default">declcall</code> is an unevaluated
operand.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
If <em>expression</em> is not a function call (<span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>), but is an
expression that 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>/2),
replace <em>expression</em> by the transformed expression for the
remainder of this subclause. Otherwise, the program is ill-formed.</p>
<p>Such a (possibly transformed) <em>expression</em> is of the form
<em>postfix-expression</em> ( <em>expression-list<sub>opt</sub></em>
).</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
If <em>postfix-expression</em> is a prvalue of pointer type
(<span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>/1), the
<code class="sourceCode default">declcall</code> expression yields an
unspecified value of the same type as <em>postfix-expression</em>, and
the <code class="sourceCode default">declcall</code> expression shall
not be potentially-evaluated.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Otherwise, let the <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>).</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
<em>F</em> is a surrogate call function (<span>12.2.2.2.3
<a href="https://wg21.link/over.call.object">[over.call.object]</a></span>/2),
the <code class="sourceCode default">declcall</code> expression yields
an unspecified value of type pointer to <em>F</em>, and the
<code class="sourceCode default">declcall</code> expression shall not be
potentially-evaluated.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
Otherwise, if <em>F</em> is a constructor, destructor, 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>), or a built-in
operator, the program is ill-formed.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
Otherwise, if <em>F</em> is an implicit object member function, the
result is a pointer to member function denoting <em>F</em>.</p>
<p>If the <em>id-expression</em> in the class member access expression
of this call is a <em>qualified-id</em>, the resulting pointer to member
function points to <em>F</em>, bypassing virtual dispatch (see compare
with <span>7.6.1.3
<a href="https://wg21.link/expr.call">[expr.call]</a></span>/2).</p>
<p>[Example:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>struct B { virtual B* f() { return this; } };</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>struct D : B { D* f() override { return this; } };</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>void g() {</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  D d;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  B&amp; rb = d;</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  auto b_f = declcall(d.B::f()); // type: B* (B::*)() </span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  auto rb_f = declcall(rb.f());  // type: B* (B::*)()</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  auto d_f = declcall(d.f());    // type: D* (D::*)()</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>  (d.*b_f)();  // B::f</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>  (d.*rb_f)(); // D::f, via virtual dispatch</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>  (d.*d_f)();  // D::f, via virtual dispatch</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<p>– end example]</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.4)</a></span>
Otherwise, when <em>F</em> is an explicit object member function, static
member function, or function, the result is a pointer to
<em>F</em>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.5)</a></span>
Otherwise, the program is ill-formed.</p></li>
</ul>

</div>
<!--
Into [temp.dep.type]{.sref}, add to the end of p10:

- [10.13]{.pnum} denoted by `decltype(@_expression_@)`, where _expression_ is type-dependent.
- [[10.14]{.pnum} denoted by `declcall(@_expression_@)`, where _expression_ is type-dependent.]{.add}
-->
<p>Into <span>13.8.3.4
<a href="https://wg21.link/temp.dep.constexpr">[temp.dep.constexpr]</a></span>,
add to list in 2.6:</p>
<div class="line-block">…<br />
<code class="sourceCode default">noexcept ( <em>expression</em> )</code><br />
<span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">declcall ( <em>expression</em> )</code></span></ins></span></div>
<p>Add feature-test macro into 17.3.2 [version.syn] in section 2</p>
<div class="add" style="color: #006e28">

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

</div>
<p>Add to Annex C:</p>
<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>
<h1 data-number="7" id="acknowledgements"><span class="header-section-number">7</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<ul>
<li>Daveed Vandevoorde for many design discussions</li>
<li>Joshua Berne, Davis Herring, Barry Revzin, Christof Meerwald, and
Brian Bi for core language review, changes, and suggestions</li>
</ul>
<h1 data-number="8" id="bibliography"><span class="header-section-number">8</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>
