<!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-05-13" />
  <title>Distinguishing between member and free coroutines</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 { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
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: 2.5em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
ol {
padding-left: 2.5em;
}
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;
}

#TOC ul > li:before {
content: none;
}
#TOC > ul {
padding-left: 0;
}

.toc-section-number {
margin-right: 0.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">Distinguishing between
member and free coroutines</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3253R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-05-13</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG, LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Brian Bi<br>&lt;<a href="mailto:bbi10@bloomberg.net" class="email">bbi10@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract</a></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">2</span> Introduction</a></li>
<li><a href="#allocation-of-coroutine-frames" id="toc-allocation-of-coroutine-frames"><span class="toc-section-number">3</span> Allocation of coroutine
frames</a></li>
<li><a href="#allocation-in-stdgenerator" id="toc-allocation-in-stdgenerator"><span class="toc-section-number">4</span> Allocation in <code class="sourceCode cpp">std<span class="op">::</span>generator</code></a></li>
<li><a href="#possible-solutions" id="toc-possible-solutions"><span class="toc-section-number">5</span> Possible solutions</a>
<ul>
<li><a href="#separate-member-type-proposed" id="toc-separate-member-type-proposed"><span class="toc-section-number">5.1</span> Separate member type
(proposed)</a></li>
<li><a href="#should-we-support-detection-of-the-ref-qualifer-not-currently-proposed" id="toc-should-we-support-detection-of-the-ref-qualifer-not-currently-proposed"><span class="toc-section-number">5.2</span> Should we support detection of the
<em>ref-qualifer</em>? (not currently proposed)</a></li>
<li><a href="#different-template-arguments-to-stdcoroutine_traits-not-proposed" id="toc-different-template-arguments-to-stdcoroutine_traits-not-proposed"><span class="toc-section-number">5.3</span> Different template arguments to
<code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>
(not proposed)</a></li>
<li><a href="#different-traits-template-not-proposed" id="toc-different-traits-template-not-proposed"><span class="toc-section-number">5.4</span> Different traits template (not
proposed)</a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">6</span> Wording</a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>A non-static member function coroutine having object parameter type
<code class="sourceCode cpp">O</code>, non-object parameter types
<code class="sourceCode cpp">P1</code>, …,
<code class="sourceCode cpp">Pn</code>, and return type
<code class="sourceCode cpp">R</code> has the same promise type as a
free function coroutine having parameter types
<code class="sourceCode cpp">O</code>,
<code class="sourceCode cpp">P1</code>, …,
<code class="sourceCode cpp">Pn</code> and return type
<code class="sourceCode cpp">R</code>. Calling the former coroutine will
always invoke the same <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
overload, with the same argument values, as a corresponding call to the
latter coroutine. It is not possible to write a promise type and <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
that can distinguish between the two cases. This limitation can force
the authors of coroutine return types such as <code class="sourceCode cpp">std<span class="op">::</span>generator</code> to
provide undesired behavior. I propose a mechanism that allows new code
to distinguish between the two cases, while not changing the behavior of
existing code.</p>
<h1 data-number="2" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Several important properties of coroutines are determined by the
coroutine’s <em>promise type</em>, defined by §<span>9.5.4
<a href="https://wg21.link/N4981#dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></span>p3 of the Standard as <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>R, P1, <span class="op">...</span>, Pn<span class="op">&gt;::</span>promise_type</code>,
where <code class="sourceCode cpp">R</code> is the return type of the
coroutine, and <code class="sourceCode cpp">P1</code>, …,
<code class="sourceCode cpp">Pn</code> is the sequence of the
coroutine’s parameter types. However, “if the coroutine is a non-static
member function”, then this list of parameter types is “preceded by the
type of the object parameter”. For example, consider the following three
coroutines.</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">struct</span> S <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    R member_coro1<span class="op">(</span><span class="dt">int</span> x, std<span class="op">::</span>string y<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    R member_coro2<span class="op">(</span><span class="kw">const</span> S<span class="op">&amp;</span>, <span class="dt">int</span> x, std<span class="op">::</span>string y<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>R free_coro<span class="op">(</span><span class="kw">const</span> S<span class="op">&amp;</span>, <span class="dt">int</span> x, std<span class="op">::</span>string y<span class="op">)</span>;</span></code></pre></div>
<p>Both <code class="sourceCode cpp">member_coro1</code> and
<code class="sourceCode cpp">free_coro</code> have promise type <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>R, <span class="kw">const</span> S<span class="op">&amp;</span>, <span class="dt">int</span>, std<span class="op">::</span>string<span class="op">&gt;::</span>promise_type</code>.
By default, this type is simply <code class="sourceCode cpp">R<span class="op">::</span>promise_type</code>
(§<span>17.12.3.2
<a href="https://wg21.link/N4981#coroutine.traits.primary">[coroutine.traits.primary]</a></span>p1),
but like most standard library traits, <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>
may be specialized if the specialization depends on at least one
program-defined type. Therefore, if
<code class="sourceCode cpp">R</code> is a program-defined type, the
author of <code class="sourceCode cpp">R</code> can make the promise
type of <code class="sourceCode cpp">member_coro1</code> and
<code class="sourceCode cpp">free_coro</code> something other than <code class="sourceCode cpp">R<span class="op">::</span>promise_type</code>,
but no matter what, these two coroutines will have the <em>same</em>
promise type.</p>
<p>If the author of class <code class="sourceCode cpp">S</code> wants to
give <code class="sourceCode cpp">member_coro1</code> a different
promise type from <code class="sourceCode cpp">free_coro</code>, they
can accomplish this by creating a separate coroutine return type, or by
making <code class="sourceCode cpp">member_coro1</code> a non-coroutine
that delegates to a private coroutine having a different signature.
However, it may often be the case that the author of the coroutine
return type <code class="sourceCode cpp">R</code> intends to make it
easy for users to write their own coroutines that return
<code class="sourceCode cpp">R</code> without understanding coroutine
internals such as the promise type. In such cases, the author of
<code class="sourceCode cpp">R</code> might wish to provide different
behavior for <code class="sourceCode cpp">member_coro1</code> and
<code class="sourceCode cpp">free_coro</code> without requiring any
special cooperation from the author of
<code class="sourceCode cpp">S</code>. In some cases—particularly, when
it comes to how the coroutine frame is allocated—the desired behavior of
<code class="sourceCode cpp">member_coro2</code> is similar to that of
<code class="sourceCode cpp">free_coro</code>.</p>
<h1 data-number="3" id="allocation-of-coroutine-frames"><span class="header-section-number">3</span> Allocation of coroutine frames<a href="#allocation-of-coroutine-frames" class="self-link"></a></h1>
<p>When a coroutine is called, the implementation usually has to
allocate storage to hold the promise type, parameter copies, and other
implementation-defined state related to the coroutine. These data are
stored in what the Standard calls the <em>coroutine state</em>, but is
most often informally referred to as the <em>coroutine frame</em>. The
coroutine frame, unless elided by the compiler, is allocated using the
promise type’s <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
if one is available, otherwise the global <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
(§<span>9.5.4
<a href="https://wg21.link/N4981#dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a></span>p9).</p>
<p>When an <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
is found in the promise type, the implementation passes the amount of
storage required as the first argument, followed by the lvalues
<code class="sourceCode cpp">p1</code>, …,
<code class="sourceCode cpp">pn</code>, which refer to the function
parameters of the coroutine, again prepended by an lvalue referring to
the object parameter, in the case of a non-static member function.
Therefore, in the example in the previous section, if
<code class="sourceCode cpp">member_coro1</code> were to be called on an
object <code class="sourceCode cpp">s</code> with non-object arguments
<code class="sourceCode cpp">x</code> and
<code class="sourceCode cpp">y</code>, and
<code class="sourceCode cpp">free_coro</code> were to be called with
arguments <code class="sourceCode cpp">s</code>,
<code class="sourceCode cpp">x</code>, and
<code class="sourceCode cpp">y</code>, then the same <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
would be called in both cases, with the same arguments.</p>
<h1 data-number="4" id="allocation-in-stdgenerator"><span class="header-section-number">4</span> Allocation in <code class="sourceCode cpp">std<span class="op">::</span>generator</code><a href="#allocation-in-stdgenerator" class="self-link"></a></h1>
<p>A concrete example of how a coroutine frame can be allocated using a
user-supplied allocator is found in the specification of the standard
library template <code class="sourceCode cpp">std<span class="op">::</span>generator</code>.
Instantiated specializations of <code class="sourceCode cpp">std<span class="op">::</span>generator</code> are
suitable as the return type of a coroutine that
<code class="sourceCode cpp">co_yields</code> a sequence of values. The
third template parameter of <code class="sourceCode cpp">std<span class="op">::</span>generator</code>,
named <code class="sourceCode cpp">Alloc</code>, is the type of the
allocator to which <code class="sourceCode cpp">std<span class="op">::</span>generator<span class="op">::</span>promise_type<span class="op">::</span><span class="kw">operator</span> <span class="kw">new</span></code>
will delegate when called to allocate memory for the coroutine frame.
The user may wish to provide a concrete
<code class="sourceCode cpp">Alloc</code> object; if one is not
provided, then a value-initialized
<code class="sourceCode cpp">Alloc</code> object is used to allocate the
coroutine frame. To provide an allocator, the user must pass the
allocator as the second argument to the coroutine, with a value of type
<code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>
as the first argument.</p>
<p>Consider the following examples of coroutines that return a <code class="sourceCode cpp">std<span class="op">::</span>generator</code>
type:</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">using</span> Generator <span class="op">=</span> std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">void</span>, std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;&gt;</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> S <span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    Generator member_coro1<span class="op">(</span>std<span class="op">::</span>allocator_arg_t,</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>                           std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span> alloc,</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>                           <span class="dt">int</span> x<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>Generator free_coro1<span class="op">(</span>std<span class="op">::</span>allocator_arg_t,</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>                     std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span> alloc,</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>                     <span class="dt">int</span> x<span class="op">)</span>;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>Generator free_coro2<span class="op">(</span><span class="kw">const</span> S<span class="op">&amp;</span>,</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>                     std<span class="op">::</span>allocator_arg_t,</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>                     std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span> alloc,</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>                     <span class="dt">int</span> x<span class="op">)</span>;</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>Generator free_coro3<span class="op">(</span><span class="kw">const</span> S<span class="op">&amp;</span>,</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>                     <span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span>,</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>                     std<span class="op">::</span>allocator_arg_t,</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>                     std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span> alloc,</span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>                     <span class="dt">int</span> x<span class="op">)</span>;</span></code></pre></div>
<p>In <code class="sourceCode cpp">member_coro</code>, because the first
parameter type is <code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>
and the second is an allocator type that is compatible with the third
template argument of <code class="sourceCode cpp">Generator</code>, the
user expects that the value of the parameter
<code class="sourceCode cpp">alloc</code> is used to allocate the
coroutine frame. The same is true for
<code class="sourceCode cpp">free_coro1</code>. In
<code class="sourceCode cpp">free_coro2</code>, on the other hand, <code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>
is in the second position. Because Standard Library containers treat
<code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>
as a special marker indicating which allocator to use only when <code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>
appears as the first parameter type, and as an ordinary parameter
otherwise, consistency with the design of the rest of the Standard
Library would require the supplied allocator to <em>not</em> be used to
allocate the coroutine frame in
<code class="sourceCode cpp">free_coro2</code> and
<code class="sourceCode cpp">free_coro3</code>.</p>
<p>What actually happens is that the supplied allocator is used to
allocate the coroutine frame in
<code class="sourceCode cpp">free_coro2</code> but not in
<code class="sourceCode cpp">free_coro3</code>. The reason for this
behavior is that, in order to use the user-supplied allocator in
<code class="sourceCode cpp">member_coro</code>, <code class="sourceCode cpp">std<span class="op">::</span>generator</code>
must define an <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
belonging to <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>Generator, <span class="kw">const</span> S<span class="op">&amp;</span>, std<span class="op">::</span>allocator_arg_t, std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span>, <span class="dt">int</span><span class="op">&gt;::</span>promise_type</code>
that accepts an argument of type
<code class="sourceCode cpp"><span class="dt">size_t</span></code>,
followed by an argument of an arbitrary class type such as
<code class="sourceCode cpp">S</code>, followed by an argument of type
<code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>,
and finally an allocator. But when
<code class="sourceCode cpp">free_coro2</code> is called, the exact same
promise type will be used by the implementation, and the exact same
<code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
overload will be called. Therefore, it is not possible for <code class="sourceCode cpp">std<span class="op">::</span>generator</code> to
use the user-supplied allocator in
<code class="sourceCode cpp">member_coro</code> without also using the
user-supplied allocator in
<code class="sourceCode cpp">free_coro2</code>. On the other hand, since
<code class="sourceCode cpp">free_coro1</code> is how a free coroutine
using the user-supplied allocator would normally be declared, it is
important to support this behavior in
<code class="sourceCode cpp">free_coro1</code>. The language rules thus
force the author of a type like <code class="sourceCode cpp">std<span class="op">::</span>generator</code> to
declare an overload of <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
that takes its allocator in the third position (after
<code class="sourceCode cpp"><span class="dt">size_t</span></code> and
<code class="sourceCode cpp">std<span class="op">::</span>allocator_arg_t</code>)
to support <code class="sourceCode cpp">free_coro1</code> as well as one
that takes its allocator in the fourth position to support
<code class="sourceCode cpp">member_coro</code> and, inadvertently,
<code class="sourceCode cpp">free_coro2</code>. The result is a
gratuitous inconsistency between the behavior of member and free
coroutines with respect to allocator parameters, and between the
behavior of <code class="sourceCode cpp">std<span class="op">::</span>generator</code> and
other Standard Library facilities that accept a user-supplied
allocator.</p>
<h1 data-number="5" id="possible-solutions"><span class="header-section-number">5</span> Possible solutions<a href="#possible-solutions" class="self-link"></a></h1>
<p>In order to make it possible for the
<code class="sourceCode cpp">member_coro</code> and
<code class="sourceCode cpp">free_coro1</code> in the previous section
to use the user-supplied allocator, while
<code class="sourceCode cpp">free_coro2</code> and
<code class="sourceCode cpp">free_coro3</code> would not, one possible
solution is to introduce a narrow fix only for <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>,
such as specifying that in the case of a member coroutine, a two-phase
overload resolution is performed in which a special argument of type,
say, <code class="sourceCode cpp">std<span class="op">::</span>object_parameter<span class="op">&lt;</span><span class="kw">const</span> S<span class="op">&amp;&gt;</span></code>
would be passed to <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
when <code class="sourceCode cpp">member_coro</code> is called. However,
I believe it would be more useful to provide a general solution allowing
<code class="sourceCode cpp">member_coro</code> and
<code class="sourceCode cpp">free_coro2</code> to have different promise
types. Such a mechanism would obviate the need for a mechanism for <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>
to determine whether it is being called to allocate a coroutine frame
for a member or free coroutine, since the two <code class="sourceCode cpp"><span class="kw">operator</span> <span class="kw">new</span></code>s
being called in those cases could simply be members of different classes
altogether.</p>
<h2 data-number="5.1" id="separate-member-type-proposed"><span class="header-section-number">5.1</span> Separate member type
(proposed)<a href="#separate-member-type-proposed" class="self-link"></a></h2>
<p>The mechanism I propose here is to add a member type called
<code class="sourceCode cpp">promise_type_for_nonstatic_member</code> to
the interface of <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>.
When a non-static member coroutine is called, the implementation first
checks whether <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>R, P1, <span class="op">...</span>, Pn<span class="op">&gt;::</span>promise_type_for_nonstatic_member</code>
(where <code class="sourceCode cpp">P1</code>, …,
<code class="sourceCode cpp">Pn</code> are defined as in §<span>9.5.4
<a href="https://wg21.link/N4981#dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a></span>p3)
is a valid type. If so, that type is the promise type for the coroutine.
If not, then the implementation falls back on <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>R, P1, <span class="op">...</span>, Pn<span class="op">&gt;::</span>promise_type</code>,
as is done in current C++. This proposal thus guarantees backward
compatibility unless, for some reason, a user chose to define
<code class="sourceCode cpp">promise_type_for_nonstatic_member</code> in
either a specialization of <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>
or their coroutine return type prior to the adoption of this
proposal.</p>
<h2 data-number="5.2" id="should-we-support-detection-of-the-ref-qualifer-not-currently-proposed"><span class="header-section-number">5.2</span> Should we support detection of
the <em>ref-qualifer</em>? (not currently proposed)<a href="#should-we-support-detection-of-the-ref-qualifer-not-currently-proposed" class="self-link"></a></h2>
<p>In both the status quo and the solution proposed above, two member
coroutines would have the same promise type if they differ only in the
presence of the
<code class="sourceCode cpp"><span class="op">&amp;</span></code>
<em>ref-qualifier</em>, since the implicit object parameter for an
implicit object member function with no <em>ref-qualifier</em> is an
lvalue reference. In order to make it possible to distinguish between
these two signatures, we would need to pass something other than the
mere implicit object parameter type to <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>.
For example, in the case of
<code class="sourceCode cpp">member_coro1</code> above, we could specify
that the implementation passes the type <code class="sourceCode cpp">Generator <span class="op">(</span>S<span class="op">::*)(</span>std<span class="op">::</span>allocator_arg_t, std<span class="op">::</span>pmr<span class="op">::</span>polymorphic_allocator<span class="op">&lt;&gt;</span>, <span class="dt">int</span><span class="op">)</span> <span class="kw">const</span></code>
when <code class="sourceCode cpp">member_coro1</code> is called<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a>; the pointer to member function type
passed for a member coroutine with a <em>ref-qualifier</em> would
include that <em>ref-qualifier</em>.</p>
<h2 data-number="5.3" id="different-template-arguments-to-stdcoroutine_traits-not-proposed"><span class="header-section-number">5.3</span> Different template arguments to
<code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>
(not proposed)<a href="#different-template-arguments-to-stdcoroutine_traits-not-proposed" class="self-link"></a></h2>
<p>Another possible solution is to invent a new Standard Library tag
type, such as <code class="sourceCode cpp">std<span class="op">::</span>member_coroutine_t</code>,
and then specify that the promise type of a non-static member coroutine
is <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">&lt;</span>R, std<span class="op">::</span>member_coroutine_t, P1, <span class="op">...</span>, Pn<span class="op">&gt;::</span>promise_type</code>
if that type is valid, otherwise falling back to status quo. (To ensure
that currently existing code would use the fallback, this strategy would
also require the primary template not to provide
<code class="sourceCode cpp">promise_type</code> when the second
template argument is <code class="sourceCode cpp">std<span class="op">::</span>member_coroutine_t</code>.)
I do not propose this solution because it could hypothetically cause
difficulties if someone were to ever find a use for a free coroutine
with first parameter type <code class="sourceCode cpp">std<span class="op">::</span>member_coroutine_t</code>
(most likely instantiated from a function template).</p>
<h2 data-number="5.4" id="different-traits-template-not-proposed"><span class="header-section-number">5.4</span> Different traits template (not
proposed)<a href="#different-traits-template-not-proposed" class="self-link"></a></h2>
<p>A third possible solution is to invent a new Standard Library traits
template, say, <code class="sourceCode cpp">std<span class="op">::</span>nonstatic_member_coroutine_traits</code>,
which would be used in case of a non-static member coroutine, with a
fallback to <code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits</code>.
I think this solution is similar to the solution using a separate member
type, but I slightly prefer keeping the specifications of the member and
non-member promise types in a single class so that any implementation
details used to compute the promise types can also be nested within that
single class. However, if the EWG reaches consensus to support detection
of the <em>ref-qualifier</em> as described above, then a separate traits
template may be superior because it would be natural to pass the pointer
to member function type as the first or second template argument to
<code class="sourceCode cpp">std<span class="op">::</span>nonstatic_member_coroutine_traits</code>,
and there is not an obvious place to pass this template argument to
<code class="sourceCode cpp">std<span class="op">::</span>coroutine_traits<span class="op">::</span>promise_type_for_nonstatic_member</code>.</p>
<h1 data-number="6" id="wording"><span class="header-section-number">6</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>Edit §<span>9.5.4
<a href="https://wg21.link/N4981#dcl.fct.def.coroutine">[dcl.fct.def.coroutine]</a></span>p3:</p>
<blockquote>
<p>The <em>promise type</em> of a coroutine is <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">std::coroutine_traits&lt;R, P1, ..., Pn&gt;::promise_type</code></span>,
where</del></span><span class="add" style="color: #006e28"><ins>defined
as follows. Let</ins></span> <code class="sourceCode cpp">R</code> <span class="rm" style="color: #bf0303"><del>is</del></span><span class="add" style="color: #006e28"><ins>be</ins></span> the return type of the
function, and <code class="sourceCode cpp">P1</code> …
<code class="sourceCode cpp">Pn</code> <span class="rm" style="color: #bf0303"><del>is</del></span>the sequence of types of the
non-object function parameters, preceded by the type of the object
parameter ([dcl.fct]) if the the coroutine is a non-static member
function. <span class="add" style="color: #006e28"><ins>If the coroutine
is a non-static member function and <span><code class="sourceCode default">std::coroutine_traits&lt;R, P1, ..., Pn&gt;::promise_type_for_nonstatic_member</code></span>
is valid and denotes a type ([temp.deduct]), the promise type is that
type. Otherwise, the promise type is <span><code class="sourceCode default">std::coroutine_traits&lt;R, P1, ..., Pn&gt;::promise_type</code></span>.</ins></span>
The promise type shall be a class type.</p>
</blockquote>
<p>In §<span>15.11
<a href="https://wg21.link/N4981#cpp.predefined">[cpp.predefined]</a></span>,
bump the value of
<code class="sourceCode cpp">__cpp_impl_coroutine</code>.</p>
<p>Replace §<span>17.12.3.2
<a href="https://wg21.link/N4981#coroutine.traits.primary">[coroutine.traits.primary]</a></span>p1
as shown:</p>
<div class="rm" style="color: #bf0303">

<blockquote>
<p>The header <code class="sourceCode default">&lt;coroutine&gt;</code>
defines the primary template
<code class="sourceCode default">coroutine_traits</code> such that if
<code class="sourceCode default">ArgTypes</code> is a parameter pack of
types and if the <em>qualified-id</em>
<code class="sourceCode default">R::promise_type</code> is valid and
denotes a type ([temp.deduct]), then <code class="sourceCode default">coroutine_traits&lt;R, ArgTypes...&gt;</code>
has the following publicly accessible member:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>  using promise_type = typename R::promise_type;</span></code></pre></div>
<p>Otherwise, <code class="sourceCode default">coroutine_traits&lt;R, ArgTypes...&gt;</code>
has no members.</p>
</blockquote>

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

<blockquote>
<p>The header <code class="sourceCode default">&lt;coroutine&gt;</code>
defines the primary template
<code class="sourceCode default">coroutine_traits</code> such that if
<code class="sourceCode default">R</code> is a type and
<code class="sourceCode default">ArgTypes</code> is a parameter pack of
types, then <code class="sourceCode default">coroutine_traits&lt;R, ArgTypes...&gt;</code>
has the following members:</p>
<ul>
<li>If <code class="sourceCode default">R::promise_type</code> is valid
and denotes a type ([temp.deduct]), then the public member <code class="sourceCode default">using promise_type = typename R::promise_type;</code>,
and no member with that name otherwise.</li>
<li>If <code class="sourceCode default">R::promise_type_for_nonstatic_member</code>
is valid and denotes a type, then the public member <code class="sourceCode default">using promise_type_for_nonstatic_member = typename R::using_promise_type_for_nonstatic_member;</code>,
and no member with that name otherwise.</li>
</ul>
</blockquote>

</div>
<p><em>Drafting note:</em> The original wording “has no members” was
probably not meant to be taken literally: even an empty class has
implicitly declared special member functions. Requiring no other
members, even with different names, is also inconsistent with prior art
(§<span>20.2.3.2
<a href="https://wg21.link/N4981#pointer.traits.types">[pointer.traits.types]</a></span>p2,
§<span>25.3.2.3
<a href="https://wg21.link/N4981#iterator.traits">[iterator.traits]</a></span>p3.4).</p>
<p>In §<span>17.3.2
<a href="https://wg21.link/N4981#version.syn">[version.syn]</a></span>,
bump the value of
<code class="sourceCode cpp">__cpp_lib_coroutine</code>.</p>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>All citations to the Standard are to working draft N4981
unless otherwise specified.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>In the case of a call through a pointer to member
function, the implementation would supply the type of that pointer to
member function, not the called member function itself, since the latter
would be unimplementable; the former is known at the call site, while
the latter may differ in the class type (§<span>7.3.13
<a href="https://wg21.link/N4981#conv.mem">[conv.mem]</a></span>p2) and
by the absence of
<code class="sourceCode cpp"><span class="kw">noexcept</span></code>
(§<span>7.3.14
<a href="https://wg21.link/N4981#conv.fctptr">[conv.fctptr]</a></span>p1).<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
