<!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="2023-05-18" />
  <title>Generator-based for loop</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: 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/vnd.microsoft.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">Generator-based for
loop</h1>
<h3 class="subtitle" style="text-align:center">Generator ranges without
coroutine overhead</h3>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2881R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-05-18</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>
      EWGI<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Jonathan Müller<br>&lt;<a href="mailto:jmueller@think-cell.com" class="email">jmueller@think-cell.com</a>&gt;<br>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@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="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract</a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation</a>
<ul>
<li><a href="#performance-of-stdgenerator-coroutines-and-iterators" id="toc-performance-of-stdgenerator-coroutines-and-iterators"><span class="toc-section-number">2.1</span> Performance of
<code class="sourceCode default">std::generator</code>, coroutines, and
iterators</a></li>
<li><a href="#inability-to-co_yield-from-nested-scope" id="toc-inability-to-co_yield-from-nested-scope"><span class="toc-section-number">2.2</span> Inability to
<code class="sourceCode default">co_yield</code> from nested
scope</a></li>
<li><a href="#limitation-to-a-single-type" id="toc-limitation-to-a-single-type"><span class="toc-section-number">2.3</span> Limitation to a single
type</a></li>
</ul></li>
<li><a href="#generator-range-idiom" id="toc-generator-range-idiom"><span class="toc-section-number">3</span>
Generator Range Idiom</a></li>
<li><a href="#proposed-design" id="toc-proposed-design"><span class="toc-section-number">4</span> Proposed Design</a>
<ul>
<li><a href="#stdcontrol_flow" id="toc-stdcontrol_flow"><span class="toc-section-number">4.1</span>
<code class="sourceCode default">std::control_flow</code></a></li>
<li><a href="#generator-based-for-loop" id="toc-generator-based-for-loop"><span class="toc-section-number">4.2</span> Generator-based
<code class="sourceCode default">for</code> loop</a></li>
<li><a href="#syntax-sugar-for-sink-calls-optional" id="toc-syntax-sugar-for-sink-calls-optional"><span class="toc-section-number">4.3</span> Syntax sugar for sink calls
(optional)</a></li>
<li><a href="#stdranges-support-future-paper" id="toc-stdranges-support-future-paper"><span class="toc-section-number">4.4</span>
<code class="sourceCode default">std::ranges</code> support (future
paper)</a></li>
</ul></li>
<li><a href="#open-questions" id="toc-open-questions"><span class="toc-section-number">5</span> Open questions</a>
<ul>
<li><a href="#spelling-of-the-generator-function" id="toc-spelling-of-the-generator-function"><span class="toc-section-number">5.1</span> Spelling of the generator
function</a></li>
<li><a href="#auto-in-for-loop" id="toc-auto-in-for-loop"><span class="toc-section-number">5.2</span>
<code class="sourceCode default">auto</code> in
<code class="sourceCode default">for</code> loop</a></li>
<li><a href="#stdstacktrace-and-__func__" id="toc-stdstacktrace-and-__func__"><span class="toc-section-number">5.3</span>
<code class="sourceCode default">std::stacktrace</code> and
<code class="sourceCode default">__func__</code></a></li>
<li><a href="#exceptions-in-for-body-and-try-catch-in-operator-for" id="toc-exceptions-in-for-body-and-try-catch-in-operator-for"><span class="toc-section-number">5.4</span> Exceptions in
<code class="sourceCode default">for</code> body and
<code class="sourceCode default">try</code>-<code class="sourceCode default">catch</code>
in <code class="sourceCode default">operator for</code></a></li>
<li><a href="#coroutine-body" id="toc-coroutine-body"><span class="toc-section-number">5.5</span>
<code class="sourceCode default">co_await</code>/<code class="sourceCode default">co_yield</code>/<code class="sourceCode default">co_return</code>
in <code class="sourceCode default">for</code> body</a></li>
<li><a href="#return-type-of-sinks" id="toc-return-type-of-sinks"><span class="toc-section-number">5.6</span> Return type of sinks</a></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">6</span> References</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>We propose language support for internal iteration in a
<code class="sourceCode default">for</code> loop by adding a
generator-based <code class="sourceCode default">for</code> loop.
Instead of using
<code class="sourceCode default">begin()</code>/<code class="sourceCode default">end()</code>,
it transforms the body of the
<code class="sourceCode default">for</code> loop into a lambda and
passes it to an overloaded
<code class="sourceCode default">operator()</code>. The lambda will then
be invoked with each element of the range.</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> generator123</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <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> sink<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>        std<span class="op">::</span>control_flow flow;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        <span class="co">// With P2561: sink(1)??;</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>        flow <span class="op">=</span> sink<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span> <span class="cf">return</span> flow;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>        <span class="co">// With P2561: sink(2)??;</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>        flow <span class="op">=</span> sink<span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span> <span class="cf">return</span> flow;</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> sink<span class="op">(</span><span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> x <span class="op">:</span> generator123<span class="op">())</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, x<span class="op">)</span>;</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>x <span class="op">==</span> <span class="dv">2</span><span class="op">)</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>        <span class="cf">break</span>;</span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>For complex ranges, iterators are a bit annoying to write: There is
an awkward split between returning the value in
<code class="sourceCode default">operator*</code> and computing the next
one in <code class="sourceCode default">operator++</code>, and any state
needs to be awkwardly stored in the iterator to turn a state
machine.</p>
<p>C++20 coroutines and C++23
<code class="sourceCode default">std::generator</code> make it a lot
more convenient. Compare e.g. the implementation of
<code class="sourceCode default">std::views::filter</code>,
<code class="sourceCode default">std::views::join</code> or the proposed
<code class="sourceCode default">std::views::concat</code> with a
generator-based implementation:</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">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Rng, <span class="kw">typename</span> Predicate<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> filter<span class="op">(</span>Rng<span class="op">&amp;&amp;</span> rng, Predicate predicate<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span>…<span class="op">&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> elem <span class="op">:</span> rng<span class="op">)</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>predicate<span class="op">(</span>elem<span class="op">))</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>            <span class="kw">co_yield</span> std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>elem<span class="op">)&gt;(</span>elem<span class="op">)</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></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Rng<span class="op">&gt;</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> join<span class="op">(</span>Rng<span class="op">&amp;&amp;</span> rng_of_rng<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span>…<span class="op">&gt;</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> rng <span class="op">:</span> rng_of_rng<span class="op">)</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>        <span class="kw">co_yield</span> std<span class="op">::</span>ranges<span class="op">::</span>elements_of<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>rng<span class="op">)&gt;(</span>rng<span class="op">))</span>;</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span> Rng<span class="op">&gt;</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> concat<span class="op">(</span>Rng<span class="op">&amp;&amp;</span> <span class="op">...</span> rng <span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span>…<span class="op">&gt;</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">((</span><span class="kw">co_yield</span> std<span class="op">::</span>ranges<span class="op">::</span>elements_of<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>rng<span class="op">)&gt;(</span>rng<span class="op">)))</span>, <span class="op">...)</span>;</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>However, ranges implemented using
<code class="sourceCode default">co_yield</code> have three
disadvantages.</p>
<h2 data-number="2.1" id="performance-of-stdgenerator-coroutines-and-iterators"><span class="header-section-number">2.1</span> Performance of
<code class="sourceCode default">std::generator</code>, coroutines, and
iterators<a href="#performance-of-stdgenerator-coroutines-and-iterators" class="self-link"></a></h2>
<p>The coroutine transformation requires heap allocation, splitting one
function into multiple, and exception machinery. This adds overhead
compared to the iterator version or a hand-written version.</p>
<p>In the simple case of benchmarking
<code class="sourceCode default">std::views::iota</code> against a
coroutine-based version, the latter is 3x slower on GCC. Note that the
coroutine uses <code class="sourceCode default">SimpleGenerator</code>
not <code class="sourceCode default">std::generator</code>.
<code class="sourceCode default">SimpleGenerator</code> already
optimizes heap allocations by using a pre-allocated buffer and
terminates on an unhandled exception. The benchmark is available on <a href="https://quick-bench.com/q/n949kUSL8_Z7Ef0-gqhjWaxXWUY">quick-bench</a>.
On clang, coroutines are better optimized, but they are still sometimes
slower than a callback-based version, especially when the range is small
and/or the computation per element cheap.</p>
<p>Just writing manual iterators instead isn’t a solution either. Common
state of the range (like
<code class="sourceCode default">filter_view</code>’s predicate) is
stored in the view, which the iterator accesses via pointer. As
compilers can rarely proof non-aliasing with pointers, the state needs
to be repeatedly reloaded for every access. The only way to get full
control over performance is to use neither iterators nor coroutines,
which is a shame.</p>
<p>Yes, in principle compilers could optimize coroutines and iterators
better, but there is a difference between having something that is only
fast because of optimizers and something that is fast by design. Only
the latter is a true zero-overhead abstraction.</p>
<h2 data-number="2.2" id="inability-to-co_yield-from-nested-scope"><span class="header-section-number">2.2</span> Inability to
<code class="sourceCode default">co_yield</code> from nested scope<a href="#inability-to-co_yield-from-nested-scope" class="self-link"></a></h2>
<p>Consider a simple tree type which is either a leaf storing an
<code class="sourceCode default">int</code> or a
<code class="sourceCode default">std::vector</code> of child nodes.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tree</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> leaf <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>variant<span class="op">&lt;</span>leaf, std<span class="op">::</span>vector<span class="op">&lt;</span>tree<span class="op">&gt;&gt;</span> impl;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Writing a coroutine-based generator that yields data cannot directly
use <code class="sourceCode default">std::visit</code>, as
<code class="sourceCode default">co_yield</code> needs to be in the
top-level scope:</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>std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> tree_data<span class="op">(</span><span class="kw">const</span> tree<span class="op">&amp;</span> t<span class="op">)</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>visit<span class="op">(</span>overloaded<span class="op">([&amp;](</span><span class="dt">int</span> data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>          <span class="kw">co_yield</span> data; <span class="co">// error</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span>, <span class="op">[&amp;](</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>tree<span class="op">&gt;&amp;</span> children<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>          <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> child <span class="op">:</span> children<span class="op">)</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>              <span class="kw">co_yield</span> std<span class="op">::</span>ranges<span class="op">::</span>elements_of<span class="op">(</span>tree_data<span class="op">(</span>child<span class="op">))</span>; <span class="co">// error</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>      <span class="op">})</span>, t<span class="op">.</span>impl<span class="op">)</span>;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Every single lambda needs to be turned into a generator as well, so
we can finally yield its elements:</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>std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> tree_data<span class="op">(</span><span class="kw">const</span> tree<span class="op">&amp;</span> t<span class="op">)</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> sub <span class="op">=</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>visit<span class="op">(</span>overloaded<span class="op">([&amp;](</span><span class="dt">int</span> data<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>            <span class="kw">co_yield</span> data;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>, <span class="op">[&amp;](</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>tree<span class="op">&gt;&amp;</span> children<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>            <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> child <span class="op">:</span> children<span class="op">)</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>                <span class="kw">co_yield</span> std<span class="op">::</span>ranges<span class="op">::</span>elements_of<span class="op">(</span>tree_data<span class="op">(</span>child<span class="op">))</span>;</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">})</span>, t<span class="op">.</span>impl<span class="op">)</span>;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">co_yield</span> std<span class="op">::</span>ranges<span class="op">::</span>elements_of<span class="op">(</span>sub<span class="op">)</span>;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This particular problem can also be solved using pattern matching,
but the underlying limitation remains: implementing a coroutine
generator cannot use “normal” helper functions as you cannot use
<code class="sourceCode default">co_yield</code> in them; they need to
be turned into generators as well. If you can’t control the helper
functions, such as the case of standard library algorithms, you simply
can’t use them.</p>
<h2 data-number="2.3" id="limitation-to-a-single-type"><span class="header-section-number">2.3</span> Limitation to a single type<a href="#limitation-to-a-single-type" class="self-link"></a></h2>
<p>As specified, <code class="sourceCode default">std::generator</code>
only produces a single type, so writing a generator of
<code class="sourceCode default">std::tuple</code> is not possible. Note
that this is only a limitation of
<code class="sourceCode default">std::generator</code> and the iterator
interface it implements, not of coroutines itself.</p>
<h1 data-number="3" id="generator-range-idiom"><span class="header-section-number">3</span> Generator Range Idiom<a href="#generator-range-idiom" class="self-link"></a></h1>
<p>In the <a href="https://github.com/think-cell/think-cell-library">think-cell-library</a>,
this problem is solved using a concept of <em>generator ranges</em>. It
is in some aspects even weaker than an input range – it can only be
iterated over, and once the iteration is stopped, it cannot resume later
on. However, it is enough for algorithms that require only a single
loop, like
<code class="sourceCode default">std::ranges::for_each</code>,
<code class="sourceCode default">std::ranges::copy</code>, or
<code class="sourceCode default">std::ranges::fold_left</code> (plus
variants and fold-like algorithms like
<code class="sourceCode default">std::ranges::any_of</code>).</p>
<p>A generator range is implemented as a type with an overloaded
<code class="sourceCode default">operator()</code> that takes another
callable, a sink. It will then use internal iteration invoking the sink
with each argument. Early exit
(i.e. <code class="sourceCode default">break</code>) is possible by
returning <code class="sourceCode default">tc::break_</code> from the
sink, which the <code class="sourceCode default">operator()</code> then
detects, stops iteration, and forwards the result.</p>
<p>Range adapters like <code class="sourceCode default">filter()</code>,
<code class="sourceCode default">join()</code> or
<code class="sourceCode default">concat()</code> are still easy to
write:</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="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Rng, <span class="kw">typename</span> Predicate<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> filter<span class="op">(</span>Rng<span class="op">&amp;&amp;</span> rng, Predicate predicate<span class="op">)</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Returned lambda is a generator range.</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">[=](</span><span class="kw">auto</span> sink<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>        <span class="co">// rng here is an iterator range, not a generator range.</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>        <span class="co">// With this proposal, it can be either, as the range-based for loop will work with both.</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Without it, generator ranges would need to be handled specially.</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> elem <span class="op">:</span> rng<span class="op">)</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>            <span class="cf">if</span> <span class="op">(</span>predicate<span class="op">(</span>elem<span class="op">))</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">{</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>                <span class="kw">auto</span> result <span class="op">=</span> sink<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>elem<span class="op">)&gt;(</span>elem<span class="op">))</span>;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> <span class="op">(</span>result <span class="op">==</span> tc<span class="op">::</span>break_<span class="op">)</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>                    <span class="cf">return</span> result;</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> tc<span class="op">::</span>continue_;</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>However, we can also yield values from nested functions:</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="kw">auto</span> tree_data<span class="op">(</span><span class="kw">const</span> tree<span class="op">&amp;</span> t<span class="op">)</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">[&amp;](</span><span class="kw">auto</span> sink<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> flow <span class="op">=</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>visit<span class="op">(</span>overloaded<span class="op">([&amp;](</span><span class="dt">int</span> data<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>                <span class="co">// Forward break/exit.</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> sink<span class="op">(</span>data<span class="op">)</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>            <span class="op">}</span>, <span class="op">[&amp;](</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>tree<span class="op">&gt;&amp;</span> children<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>                <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> child <span class="op">:</span> children<span class="op">)</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>                <span class="op">{</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>                    <span class="kw">auto</span> flow <span class="op">=</span> tree_data<span class="op">(</span>child<span class="op">)(</span>sink<span class="op">)</span>;</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>                    <span class="cf">if</span> <span class="op">(</span>flow <span class="op">==</span> tc<span class="op">::</span>break_<span class="op">)</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>                      <span class="co">// Forward early break and do actually break.</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>                      <span class="cf">return</span> flow;</span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>                <span class="op">}</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> tc<span class="op">::</span>continue_;</span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>            <span class="op">})</span>, t<span class="op">.</span>impl<span class="op">)</span>;</span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> flow;</span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>As shown in the benchmark, the performance is comparable to the range
implementation and in think-cell’s experience often even faster.</p>
<h1 data-number="4" id="proposed-design"><span class="header-section-number">4</span> Proposed Design<a href="#proposed-design" class="self-link"></a></h1>
<p>The proposed design consists of two mandatory parts and optional
syntax sugar.</p>
<h2 data-number="4.1" id="stdcontrol_flow"><span class="header-section-number">4.1</span>
<code class="sourceCode default">std::control_flow</code><a href="#stdcontrol_flow" class="self-link"></a></h2>
<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="kw">namespace</span> std</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">/// A control flow tag type and object that means `continue`.</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> continue_t</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Empty.</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">operator</span> std<span class="op">::</span>true_type<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> std<span class="op">::</span>false_type <span class="kw">operator</span><span class="op">!()</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a>        <span class="kw">friend</span> std<span class="op">::</span>strong_ordering <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>continue_t, continue_t<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</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>    <span class="kw">inline</span> <span class="kw">constexpr</span> continue_t continue_;</span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a>    <span class="co">/// A control flow tag type and object that means `break`.</span></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">(</span><span class="st">&quot;need to forward break&quot;</span><span class="op">)]]</span> break_t</span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Empty.</span></span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">operator</span> std<span class="op">::</span>false_type<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> std<span class="op">::</span>true_type <span class="kw">operator</span><span class="op">!()</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb8-33"><a href="#cb8-33" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb8-34"><a href="#cb8-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-35"><a href="#cb8-35" aria-hidden="true" tabindex="-1"></a>        <span class="kw">friend</span> std<span class="op">::</span>strong_ordering <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>break_t, break_t<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-36"><a href="#cb8-36" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-37"><a href="#cb8-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> break_t break_;</span>
<span id="cb8-38"><a href="#cb8-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-39"><a href="#cb8-39" aria-hidden="true" tabindex="-1"></a>    <span class="co">/// A control flow object that can mean `continue`, `break` or some implementation-defined `break`-like state.</span></span>
<span id="cb8-40"><a href="#cb8-40" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> <span class="op">[[</span><span class="at">nodiscard</span><span class="op">(</span><span class="st">&quot;need to forward control flow&quot;</span><span class="op">)]]</span> control_flow</span>
<span id="cb8-41"><a href="#cb8-41" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb8-42"><a href="#cb8-42" aria-hidden="true" tabindex="-1"></a>    <span class="kw">public</span><span class="op">:</span></span>
<span id="cb8-43"><a href="#cb8-43" aria-hidden="true" tabindex="-1"></a>        <span class="co">/// Create a control flow object that means `continue`.</span></span>
<span id="cb8-44"><a href="#cb8-44" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> control_flow<span class="op">(</span>continue_t<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb8-45"><a href="#cb8-45" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> control_flow<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">:</span> control_flow<span class="op">(</span>continue_<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb8-46"><a href="#cb8-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-47"><a href="#cb8-47" aria-hidden="true" tabindex="-1"></a>        <span class="co">/// Create a control flow object that means `break`.</span></span>
<span id="cb8-48"><a href="#cb8-48" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> control_flow<span class="op">(</span>break_t<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb8-49"><a href="#cb8-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-50"><a href="#cb8-50" aria-hidden="true" tabindex="-1"></a>        <span class="co">/// Trivially copyable.</span></span>
<span id="cb8-51"><a href="#cb8-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-52"><a href="#cb8-52" aria-hidden="true" tabindex="-1"></a>        <span class="co">/// Return `true` if the control flow means `continue`, `false` otherwise.</span></span>
<span id="cb8-53"><a href="#cb8-53" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">explicit</span> <span class="kw">operator</span> <span class="dt">bool</span><span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb8-54"><a href="#cb8-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-55"><a href="#cb8-55" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>control_flow, control_flow<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb8-56"><a href="#cb8-56" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">friend</span> std<span class="op">::</span>strong_ordering <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>control_flow, control_flow<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb8-57"><a href="#cb8-57" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-58"><a href="#cb8-58" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><code class="sourceCode default">std::control_flow</code> is a class
that represents a <code class="sourceCode default">break</code> or
<code class="sourceCode default">continue</code> result of a function.
It is essentially a strongly-typed version of
<code class="sourceCode default">bool</code>, where
<code class="sourceCode default">true</code> means
<code class="sourceCode default">continue_</code> and
<code class="sourceCode default">false</code> means
<code class="sourceCode default">break_</code>. However, an
implementation may give it additional states such as
<code class="sourceCode default">return</code> (which maps to
<code class="sourceCode default">break</code>) or
<code class="sourceCode default">goto label</code> (which also maps to
<code class="sourceCode default">break</code>).</p>
<p>Note that <code class="sourceCode default">std::continue_</code> and
<code class="sourceCode default">std::break_</code> are not just a named
constant of type
<code class="sourceCode default">std::control_flow</code>, but of a
distinct tag type, which has an implicit conversion to
<code class="sourceCode default">std::true/false_type</code> and a
likewise constant <code class="sourceCode default">operator!</code>.
This ensures that the common case of “always continue” or “always break”
can be encoded in the type system and guarantee optimizations.</p>
<p>The standardization of
<code class="sourceCode default">std::control_flow</code> is the bare
minimum to enable writing generator ranges:</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> generator123</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// `sink` takes the type yielded by the generator range.</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// and returns `std::control_flow`, `std::continue_t`, or `std::break_t`.</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <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> sink<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>control_flow</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>        std<span class="op">::</span>control_flow flow;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>        flow <span class="op">=</span> sink<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span> <span class="cf">return</span> flow;</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>        flow <span class="op">=</span> sink<span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span> <span class="cf">return</span> flow;</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="cf">return</span> sink<span class="op">(</span><span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Generator<span class="op">&gt;</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> use_generator_range<span class="op">(</span>Generator<span class="op">&amp;&amp;</span> generator<span class="op">)</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>    generator<span class="op">([](</span><span class="kw">auto</span> value<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, value<span class="op">)</span>;</span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Unconditionally continue generating.</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a>    generator<span class="op">([](</span><span class="kw">auto</span> value<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>control_flow <span class="op">{</span></span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a>        <span class="co">// Exit early if we see the value 42.</span></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>value <span class="op">==</span> <span class="dv">42</span><span class="op">)</span></span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> std<span class="op">::</span>break_;</span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, value<span class="op">)</span>;</span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The remaining features are “just” language support to make this idiom
nicer.</p>
<h2 data-number="4.2" id="generator-based-for-loop"><span class="header-section-number">4.2</span> Generator-based
<code class="sourceCode default">for</code> loop<a href="#generator-based-for-loop" class="self-link"></a></h2>
<table>
<caption><blockquote>
<p>Basic lowering of a generator-based
<code class="sourceCode default">for</code> loop.</p>
</blockquote></caption>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>User code</strong>
</div></th>
<th><div style="text-align:center">
<strong>Lowered code</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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="cf">for</span> <span class="op">(</span><em>T</em> <em>binding</em> <span class="op">:</span> <em>object</em><span class="op">)</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <em>body</em></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<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="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> __body <span class="op">=</span> <span class="op">[&amp;](</span><em>T</em><span class="op">&amp;&amp;</span> __element<span class="op">)</span> <span class="op">-&gt;</span> <em>see-below</em> <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>        <em>T</em> <em>binding</em> <span class="op">=</span> std<span class="op">::</span>forward<span class="op">&lt;</span><em>T</em><span class="op">&gt;(</span>__element<span class="op">)</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>        <em>body</em></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">})</span>;</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> __flow <span class="op">=</span> <em>object</em><span class="op">(</span>__body<span class="op">)</span>;</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <em>see-below</em></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>Previously, the range-based
<code class="sourceCode default">for</code> loop was always lowered to
an <em>iterator-based <code class="sourceCode default">for</code>
loop</em> if the type has
<code class="sourceCode default">begin()</code> and
<code class="sourceCode default">end()</code>. We propose that it can
also be lowered to a <em>generator-based
<code class="sourceCode default">for</code> loop</em> if the type has an
<code class="sourceCode default">operator()</code> that accepts a
callable and returns
<code class="sourceCode default">std::control_flow</code>,
<code class="sourceCode default">std::break_t</code> or
<code class="sourceCode default">std::continue_t</code>. If the type has
both <code class="sourceCode default">begin()</code> and
<code class="sourceCode default">end()</code>, the generator-based
version is preferred as it is expected to be faster.</p>
<p>The <code class="sourceCode default">for</code> loop is lowered to a
call to <code class="sourceCode default">operator()</code> on the
generator, passing it the body of the loop transformed into a lambda.
That lambda takes the type specified in the binding of the loop
qualified with <code class="sourceCode default">&amp;&amp;</code>.
Reference collapsing rules ensure that it is turned into an lvalue
reference if necessary. The extra step is necessary as the binding of
the <code class="sourceCode default">for</code>-loop might be a
structured binding which is not allowed as a lambda argument. The lambda
body then consists of the binding of the range-based
<code class="sourceCode default">for</code> loop, the body of the loop,
and a (potentially unreachable)
<code class="sourceCode default">return std::continue_</code>.</p>
<p>The loop body is kept as-is, except for control flow statements which
need to be translated:</p>
<ul>
<li>A top-level <code class="sourceCode default">continue;</code> is
transformed to
<code class="sourceCode default">return std::continue_</code>.</li>
<li>A top-level <code class="sourceCode default">break;</code> is
transformed to
<code class="sourceCode default">return std::break_</code>.</li>
<li>A <code class="sourceCode default">return;</code> is transformed to
<code class="sourceCode default">return <em>implementation-defined</em></code>,
which has the same effect as
<code class="sourceCode default">std::break_</code> but also causes the
compiler to forward the <code class="sourceCode default">return</code>
after the loop.</li>
<li>A <code class="sourceCode default">return <em>expr</em>;</code> is
transformed to something that evaluates
<code class="sourceCode default"><em>expr</em></code> and stores it
somewhere, before a <code class="sourceCode default">return <em>implementation-defined</em></code>
which has the same effect as
<code class="sourceCode default">std::break_</code> but also causes the
compiler to forward the <code class="sourceCode default">return</code>
after the loop.</li>
<li>A <code class="sourceCode default">goto</code> that exits the
range-based <code class="sourceCode default">for</code> loop is
transformed to <code class="sourceCode default">return <em>implementation-defined</em></code>,
which has the same effect as
<code class="sourceCode default">std::break_</code> but also causes the
compiler to forward the <code class="sourceCode default">goto</code>
after the loop.</li>
<li>A <code class="sourceCode default">throw</code> is kept as-is.</li>
<li>A
<code class="sourceCode default">co_await</code>/<code class="sourceCode default">co_yield</code>/<code class="sourceCode default">co_return</code>
is ill-formed (but <a href="#coroutine-body">see below</a> for a
discussion about that).</li>
</ul>
<p>The return type of the lambda is
<code class="sourceCode default">std::continue_t</code> or
<code class="sourceCode default">std::break_t</code> if that is the only
returned control-flow case, or
<code class="sourceCode default">std::control_flow</code> otherwise. If
the lambda exits with an exception or returns
<code class="sourceCode default">std::break_</code> it must not be
called again. The return value of the lambda must be forwarded through
the <code class="sourceCode default">operator()</code>.</p>
<p>After the call to <code class="sourceCode default">operator()</code>,
the compiler may insert additional code to handle a
<code class="sourceCode default">return</code> or
<code class="sourceCode default">goto</code> of the body, to ensure that
control flow jumps to the desired location.</p>
<table>
<caption><blockquote>
<p>Example lowering.</p>
</blockquote></caption>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>User code</strong>
</div></th>
<th><div style="text-align:center">
<strong>Lowered code</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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="cf">for</span> <span class="op">(</span><span class="dt">int</span> x <span class="op">:</span> generator123<span class="op">())</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><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="op">(</span>x <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">continue</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>x <span class="op">==</span> <span class="dv">2</span><span class="op">)</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">break</span>;</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>printf<span class="op">(</span><span class="st">&quot;</span><span class="sc">%d\n</span><span class="st">&quot;</span>, x<span class="op">)</span>;</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<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="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> __body <span class="op">=</span> <span class="op">[&amp;](</span><span class="dt">int</span><span class="op">&amp;&amp;</span> __element<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>control_flow <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> x <span class="op">=</span> __element;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>x <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>x <span class="op">==</span> <span class="dv">2</span><span class="op">)</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> std<span class="op">::</span>break_;</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>printf<span class="op">(</span><span class="st">&quot;</span><span class="sc">%d\n</span><span class="st">&quot;</span>, x<span class="op">)</span>;</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> __flow <span class="op">=</span> generator123<span class="op">()(</span>__body<span class="op">)</span>;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span><span class="dt">void</span><span class="op">)</span>__flow;</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>More example lowerings are given on <a href="https://godbolt.org/z/1bGYjYq3s">godbolt</a>. Note that the
compiler may do a more efficient job during codegen than what we can
express in C++. In particular,
<code class="sourceCode default">return <em>expr</em></code> must
directly construct the expression in the return slot to enable copy
elision.</p>
<h2 data-number="4.3" id="syntax-sugar-for-sink-calls-optional"><span class="header-section-number">4.3</span> Syntax sugar for sink calls
(optional)<a href="#syntax-sugar-for-sink-calls-optional" class="self-link"></a></h2>
<p>The implementation of a generator will necessarily have code that
invoke the sink and does an early return:</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="kw">auto</span> flow <span class="op">=</span> sink<span class="op">(</span>value<span class="op">)</span>;</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span> <span class="cf">return</span> flow;</span></code></pre></div>
<p>This is annoying, but also precisely the pattern <span class="citation" data-cites="P2561R1">[<a href="#ref-P2561R1" role="doc-biblioref">P2561R1</a>]</span> sets out to solve with its
error propagation operator. If adopted, we can instead write:</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>sink<span class="op">(</span>value<span class="op">)??</span>;</span></code></pre></div>
<p>Alternatively, we could keep the association with coroutine
generators and use a special
<code class="sourceCode default">co_yield</code>-into statement:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">co_yield</span><span class="op">(</span>sink<span class="op">)</span> value;</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co">// or</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">co_yield</span><span class="op">(</span>sink, value<span class="op">)</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="co">// or</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">co_yield</span><span class="op">[</span>sink<span class="op">]</span> value;</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="co">// or</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="kw">co_yield</span><span class="op">&lt;</span>sink<span class="op">&gt;</span> value;</span></code></pre></div>
<p>However, re-using <code class="sourceCode default">co_yield</code> in
that way might result in parsing ambiguities with regular coroutine
<code class="sourceCode default">co_yield</code>, so that particular
syntax might be unfeasible.</p>
<h2 data-number="4.4" id="stdranges-support-future-paper"><span class="header-section-number">4.4</span>
<code class="sourceCode default">std::ranges</code> support (future
paper)<a href="#stdranges-support-future-paper" class="self-link"></a></h2>
<p>If there is interest in the feature, a separate paper will add
support for generator ranges to the standard library. This includes
concepts for generator ranges, turning views into generator ranges for
better iteration performance, and adding support for generator ranges to
single-loop range algorithms like
<code class="sourceCode default">std::ranges::for_each</code>,
<code class="sourceCode default">std::ranges::copy</code>, or
<code class="sourceCode default">std::ranges::fold_left</code> (plus
variants and fold-like algorithms like
<code class="sourceCode default">std::ranges::any_of</code>).</p>
<h1 data-number="5" id="open-questions"><span class="header-section-number">5</span> Open questions<a href="#open-questions" class="self-link"></a></h1>
<h2 data-number="5.1" id="spelling-of-the-generator-function"><span class="header-section-number">5.1</span> Spelling of the generator
function<a href="#spelling-of-the-generator-function" class="self-link"></a></h2>
<p>As proposed, the generator-based
<code class="sourceCode default">for</code> loop is triggered when the
range type has an <code class="sourceCode default">operator()</code>
that takes a sink and returns
<code class="sourceCode default">std::control_flow</code>,
<code class="sourceCode default">std::break_t</code>, or
<code class="sourceCode default">std::continue_t</code>. This spelling
has the advantage that lambdas can directly be used as generators. For
example, if the range adapters were updated to use generator ranges
(like the ones in the think-cell-library), we could write code like
this:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Copy a C FILE to a buffer.</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> sink<span class="op">)</span> <span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>control_flow flow;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">while</span> <span class="op">(</span><span class="kw">true</span><span class="op">)</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> c <span class="op">=</span> std<span class="op">::</span>fgetc<span class="op">(</span>file<span class="op">)</span>;</span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>c <span class="op">==</span> EOF<span class="op">)</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>            <span class="cf">break</span>;</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>        flow <span class="op">=</span> sink<span class="op">(</span>c<span class="op">)</span>;</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(!</span>flow<span class="op">)</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span>;</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> flow;</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>, buffer<span class="op">)</span>;</span></code></pre></div>
<p>However, we are open to a different spelling. An early draft of the
paper used <code class="sourceCode default">operator for</code> instead
of <code class="sourceCode default">operator()</code>, where
<code class="sourceCode default">operator for</code> is a new
overloadable operator. This can make it more obvious that a type has
custom behavior when used with a range-based
<code class="sourceCode default">for</code> loop.</p>
<p>Using <code class="sourceCode default">operator for</code> means that
lambdas no longer work as-is and would need to be wrapped into a type
that has an <code class="sourceCode default">operator for</code> which
calls the lambda. That works, but is also a bit unnecessary.
Alternatively, a lambda that takes a sink and returns a type like
<code class="sourceCode default">std::control_flow</code> could
automatically get an
<code class="sourceCode default">operator for</code> overload. Either
the language provides one as member, or the standard library provides a
generic non-member overload for callables. At that point, we might as
well use <code class="sourceCode default">operator()</code> again
though.</p>
<h2 data-number="5.2" id="auto-in-for-loop"><span class="header-section-number">5.2</span>
<code class="sourceCode default">auto</code> in
<code class="sourceCode default">for</code> loop<a href="#auto-in-for-loop" class="self-link"></a></h2>
<p>What should happen if the <code class="sourceCode default">for</code>
loop uses <code class="sourceCode default">auto</code> for the type of
the loop variable?</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> x <span class="op">:</span> generator123<span class="op">())</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>    …</span></code></pre></div>
<p>With the specification of
<code class="sourceCode default">operator()</code> it is very difficult
for the compiler to figure out what is the actual value type of the
<code class="sourceCode default">operator()</code> – it has to look in
the body to see what is passed to the callable. There is also no
limitation to only one type; an implementation may invoke the sink with
different types.</p>
<p>There are three approaches to avoid the deduction:</p>
<ol type="1">
<li>Make it ill-formed. When the user wants to use a generator-based
<code class="sourceCode default">for</code> loop, they have to specify a
type for the loop variable.</li>
<li>Infer the type from somewhere else, maybe some trait that has to
specialized or a member typedef given. Note that we cannot use the
return type of <code class="sourceCode default">operator()</code> as
that is <code class="sourceCode default">std::control_flow</code> or
related.</li>
<li>Turn the body of the <code class="sourceCode default">for</code>
loop into a generic lambda with an
<code class="sourceCode default">auto</code> parameter instead of a
fixed type.</li>
<li>As above, but make the program ill-formed if the lambda would be
instantiated with multiple different types. In a way, the
<code class="sourceCode default">auto</code> parameter in that
particular compiler-generated lambda then would be more like the
<code class="sourceCode default">auto</code> in a return type or
variable declaration: a way to name a specific, yet unknown type, and
not a template.</li>
</ol>
<p>Option 1 is annoying. Option 2 is not easy because the type of the
range depends on the cv-ref qualifications of
<code class="sourceCode default">*this</code>. think-cell uses
<code class="sourceCode default">decltype()</code> of a member function
call for that purpose:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> container</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Non-const containers yield `int&amp;`.</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span><span class="op">&amp;</span> generator_output_type<span class="op">()</span>;  <span class="co">// no definition</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// const containers yield `const int&amp;`.</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="dt">int</span><span class="op">&amp;</span> generator_output_type<span class="op">()</span> <span class="kw">const</span>; <span class="co">// no definition</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> generator_output_type <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>declval<span class="op">&lt;</span>T<span class="op">&gt;().</span>generator_output_type<span class="op">())</span>;</span></code></pre></div>
<p>However, adding an undefined member function might be a bit too weird
for the standard.</p>
<p>Option 3 has the side-effect of allowing iteration of types like
<code class="sourceCode default">std::tuple</code>:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> <span class="op">...</span> T<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tuple</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> sink<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> generator_impl<span class="op">(</span>std<span class="op">::</span>index_sequence_for<span class="op">&lt;</span>T<span class="op">...&gt;{}</span>, sink<span class="op">)</span>;</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span> <span class="op">...</span> Idx, <span class="kw">typename</span> Fn<span class="op">&gt;</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> generator_impl<span class="op">(</span>std<span class="op">::</span>index_sequence<span class="op">&lt;</span>Idx<span class="op">...&gt;</span>, Fn<span class="op">&amp;&amp;</span> sink<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>common_type_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>sink<span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>Idx<span class="op">&gt;(*</span><span class="kw">this</span><span class="op">)))...&gt;</span> flow;</span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>        <span class="co">// &amp;&amp; short-circuits once we have a break-like control flow.</span></span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">((</span>flow <span class="op">=</span> sink<span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>Idx<span class="op">&gt;(*</span><span class="kw">this</span><span class="op">)))</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span>;</span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> flow;</span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>…</span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> elem <span class="op">:</span> std<span class="op">::</span>make_tuple<span class="op">(</span><span class="dv">42</span>, <span class="fl">3.14</span><span class="bu">f</span>, <span class="st">&quot;hello&quot;</span><span class="op">))</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, elem<span class="op">)</span>;</span></code></pre></div>
<p>This is a different way of implementing expansion statements <span class="citation" data-cites="P1306R1">[<a href="#ref-P1306R1" role="doc-biblioref">P1306R1</a>]</span>.</p>
<p>Even if EWG doesn’t want to support multiple output types for
<code class="sourceCode default">for</code>, the library idiom of using
<code class="sourceCode default">operator()</code> naturally supports
it. Limiting the idiom just for the sake of the language feature is
wrong – we still might want to iterate tuples by calling
<code class="sourceCode default">operator()</code> manually. It is
better to just constrain the use in
<code class="sourceCode default">for</code> but not the general spelling
of the generator function, as done in option 4.</p>
<h2 data-number="5.3" id="stdstacktrace-and-__func__"><span class="header-section-number">5.3</span>
<code class="sourceCode default">std::stacktrace</code> and
<code class="sourceCode default">__func__</code><a href="#stdstacktrace-and-__func__" class="self-link"></a></h2>
<p>What does the following code print?</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">()</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> x <span class="op">:</span> generator123<span class="op">())</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="ot">__func__</span> <span class="op">&lt;&lt;</span> <span class="ch">&#39; &#39;</span> <span class="op">&lt;&lt;</span> std<span class="op">::</span>stacktrace<span class="op">::</span>current<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Does it print the name <code class="sourceCode default">foo</code>
and the stack trace beginning at
<code class="sourceCode default">foo</code>, as that is what it looks
like syntactically, or does it report the true stack trace involving the
compiler generated lambda and arbitrarily many calls caused by
<code class="sourceCode default">operator()</code>?</p>
<p>The authors prefer the second choice where a stack trace reports the
true stack trace and not the syntactic one.</p>
<h2 data-number="5.4" id="exceptions-in-for-body-and-try-catch-in-operator-for"><span class="header-section-number">5.4</span> Exceptions in
<code class="sourceCode default">for</code> body and
<code class="sourceCode default">try</code>-<code class="sourceCode default">catch</code>
in <code class="sourceCode default">operator for</code><a href="#exceptions-in-for-body-and-try-catch-in-operator-for" class="self-link"></a></h2>
<p>We expect that the following code will
<code class="sourceCode default">throw</code> on the first iteration
(assuming the range is
<code class="sourceCode default">[1, 2, 3]</code>) and thus never call
<code class="sourceCode default">g()</code> or
<code class="sourceCode default">h()</code>.</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> x <span class="op">:</span> generator123<span class="op">())</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>x <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="cf">throw</span> <span class="dv">42</span>;</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>    g<span class="op">()</span>;</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>h<span class="op">()</span>;</span></code></pre></div>
<p>But what if we have a somewhat malicious
<code class="sourceCode default">operator()</code> implementation that
swallows all exceptions?</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> generator123</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <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> sink<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>        <span class="cf">try</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> sink<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{}</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>As specified, the exception propagates out of
<code class="sourceCode default">sink()</code> and is then discarded by
the <code class="sourceCode default">operator()</code>, so we will call
<code class="sourceCode default">h()</code>.</p>
<p>There are three approaches here:</p>
<ol type="1">
<li>Do nothing. If someone writes a malicious
<code class="sourceCode default">operator()</code>, that’s on them.</li>
<li>Make exceptions thrown inside the generated lambda uncatchable until
they’ve left <code class="sourceCode default">operator()</code>. Using
some compiler magic, we set a flag or something on the exception which
disables
<code class="sourceCode default">try</code>/<code class="sourceCode default">catch</code>.
Once the exception has left the
<code class="sourceCode default">operator()</code>, the flag is reset.
This makes it impossible to catch exceptions thrown by the sink until
they’re back in the syntactic scope.</li>
<li>Make exceptions thrown inside the generated lambda implicitly
re-thrown when caught in
<code class="sourceCode default">operator()</code>. Similar to 2, but
<code class="sourceCode default">operator for</code> is allowed to see
the exception, just not to swallow them. After a
<code class="sourceCode default">catch</code>, exceptions are
automatically re-thrown.</li>
</ol>
<p>The problem with 2 is that a generator might change itself during
iteration inside <code class="sourceCode default">operator()</code>.
When an exception is thrown, it needs to detect that to restore its
previous state. The problem with 3 is potential overhead caused by the
extra exception machinery, which we don’t want to pay only to guard
against malicious actors. Keep in mind that the
<code class="sourceCode default">operator()</code>, the call to the
<code class="sourceCode default">sink</code>, and a
<code class="sourceCode default">try</code>/<code class="sourceCode default">catch</code>
surrounding the sink might be separated by an arbitrary amount of
intermediate function calls, so it cannot be done statically. As such,
the authors prefer option 1.</p>
<h2 data-number="5.5" id="coroutine-body"><span class="header-section-number">5.5</span>
<code class="sourceCode default">co_await</code>/<code class="sourceCode default">co_yield</code>/<code class="sourceCode default">co_return</code>
in <code class="sourceCode default">for</code> body<a href="#coroutine-body" class="self-link"></a></h2>
<p>When a user <code class="sourceCode default">co_await</code>s or
<code class="sourceCode default">co_yield</code>s inside the body of a
generator-based <code class="sourceCode default">for</code> loop, we
have a problem since we’re no longer inside a coroutine, but a
compiler-generated lambda. To handle that properly both the compiler
generated lambda and the
<code class="sourceCode default">operator()</code> needs to be turned
into coroutines to properly propagate the
<code class="sourceCode default">co_await</code>.</p>
<p>While that could work for the compiler-generated lambda, it would be
problematic for the <code class="sourceCode default">operator()</code>,
as we now sometimes need
<code class="sourceCode default">co_await</code> on the sink. This
problem relates to the general problem of coroutines with generic code,
and is best solved by a general solution for conditional
<code class="sourceCode default">co_await</code> in generic code.</p>
<p>We thus propose to make it ill-formed to use coroutine statements in
the body of a generator-based
<code class="sourceCode default">for</code> loop (at least for now).
Alternatively, we could instead silently fallback to the traditional
iterator-based <code class="sourceCode default">for</code> loop which
does not suffer from this problem. This works nicely with generic code,
but requires that the type also has
<code class="sourceCode default">begin()</code> and
<code class="sourceCode default">end()</code> (otherwise it is
ill-formed again).</p>
<h2 data-number="5.6" id="return-type-of-sinks"><span class="header-section-number">5.6</span> Return type of sinks<a href="#return-type-of-sinks" class="self-link"></a></h2>
<p>The implementation in think-cell allows arbitrary return types for
the sink, not just
<code class="sourceCode default">std::control_flow</code> and related
types. If a type is not a control flow type including
<code class="sourceCode default">void</code>, it is treated as
<code class="sourceCode default">std::continue_</code>. That way, if a
sink is written by hand or wraps an existing function, if it doesn’t
want an early return, it doesn’t need to do anything. Otherwise, it
would need to add an unnecessary
<code class="sourceCode default">return std::continue_</code>.</p>
<p>If a generator range is only used with the range-based
<code class="sourceCode default">for</code> loop, this is not necessary
as the compiler generated sink will always have the right type, but in
think-cell’s experience where generators can be used with arbitrary
algorithms and their hand-written lambdas, it is very convenient if the
work of adjusting the return type is moved from the caller to the
generator implementation.</p>
<p>Relaxing the return type complicates the implementation for sink
calls, which now need to translate an arbitrary type (including void) to
<code class="sourceCode default">std::continue_t</code> before
branching. As such, it is useful to have a standardized helper function
for that logic, e.g. a <code class="sourceCode default">std::control_flow::invoke(sink, value)</code>:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Sink, <span class="kw">typename</span> <span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> std<span class="op">::</span>control_flow<span class="op">::</span>invoke<span class="op">(</span>Sink<span class="op">&amp;&amp;</span> sink, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> result <span class="op">=</span> std<span class="op">::</span>invoke_result_t<span class="op">&lt;</span>Sink<span class="op">&amp;&amp;</span>, Args<span class="op">&amp;&amp;...&gt;</span>;</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>result, std<span class="op">::</span>control_flow<span class="op">&gt;</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>               <span class="op">||</span> std<span class="op">::</span>is_same_v<span class="op">&lt;</span>result, std<span class="op">::</span>continue_t<span class="op">&gt;</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>               <span class="op">||</span> std<span class="op">::</span>is_same_v<span class="op">&lt;</span>result, std<span class="op">::</span>break_t<span class="op">&gt;)</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>invoke<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sink<span class="op">&gt;(</span>sink<span class="op">)</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Args<span class="op">&gt;(</span>args<span class="op">)...)</span>;</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>invoke<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sink<span class="op">&gt;(</span>sink<span class="op">)</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Args<span class="op">&gt;(</span>args<span class="op">)...)</span>;</span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>continue_;</span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Alternatively, the selected syntax sugar could be specified to do the
translation as well.</p>
<h1 data-number="6" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="list">
<div id="ref-P1306R1" class="csl-entry" role="listitem">
[P1306R1] Andrew Sutton, Sam Goodrick, Daveed Vandevoorde. 2019-01-21.
Expansion statements. <a href="https://wg21.link/p1306r1"><div class="csl-block">https://wg21.link/p1306r1</div></a>
</div>
<div id="ref-P2561R1" class="csl-entry" role="listitem">
[P2561R1] Barry Revzin. 2022-10-11. An error propagation operator. <a href="https://wg21.link/p2561r1"><div class="csl-block">https://wg21.link/p2561r1</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
