<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2025-01-12" />
  <title>High-Quality Sender Diagnostics with Constexpr
Exceptions</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">High-Quality Sender
Diagnostics with Constexpr Exceptions</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3557R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-01-12</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      LEWG Library Evolution<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Eric Niebler<br>&lt;<a href="mailto:eric.niebler@gmail.com" class="email">eric.niebler@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#executive-summary" id="toc-executive-summary"><span class="toc-section-number">2</span> Executive
Summary<span></span></a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">3</span> Revision History<span></span></a>
<ul>
<li><a href="#r0" id="toc-r0"><span class="toc-section-number">3.1</span> R0<span></span></a></li>
</ul></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">4</span> Motivation<span></span></a></li>
<li><a href="#proposed-design-necessary-changes" id="toc-proposed-design-necessary-changes"><span class="toc-section-number">5</span> Proposed Design, Necessary
Changes<span></span></a>
<ul>
<li><a href="#get_completion_signatures" id="toc-get_completion_signatures"><span class="toc-section-number">5.1</span>
<code class="sourceCode default">get_completion_signatures</code><span></span></a>
<ul>
<li><a href="#non-non-dependent-senders" id="toc-non-non-dependent-senders"><span class="toc-section-number">5.1.1</span> Non-non-dependent
senders<span></span></a></li>
<li><a href="#implementation" id="toc-implementation"><span class="toc-section-number">5.1.2</span>
Implementation<span></span></a></li>
</ul></li>
<li><a href="#sender_in" id="toc-sender_in"><span class="toc-section-number">5.2</span>
<code class="sourceCode default">sender_in</code><span></span></a></li>
<li><a href="#basic-sender" id="toc-basic-sender"><span class="toc-section-number">5.3</span>
<em><code class="sourceCode default">basic-sender</code></em><span></span></a></li>
<li><a href="#dependent_sender" id="toc-dependent_sender"><span class="toc-section-number">5.4</span>
<code class="sourceCode default">dependent_sender</code><span></span></a></li>
</ul></li>
<li><a href="#proposed-design-nice-to-haves" id="toc-proposed-design-nice-to-haves"><span class="toc-section-number">6</span> Proposed Design,
Nice-to-haves<span></span></a>
<ul>
<li><a href="#completion_signatures" id="toc-completion_signatures"><span class="toc-section-number">6.1</span>
<code class="sourceCode default">completion_signatures</code><span></span></a></li>
<li><a href="#make_completion_signatures" id="toc-make_completion_signatures"><span class="toc-section-number">6.2</span>
<code class="sourceCode default">make_completion_signatures</code><span></span></a></li>
<li><a href="#transform_completion_signatures" id="toc-transform_completion_signatures"><span class="toc-section-number">6.3</span>
<code class="sourceCode default">transform_completion_signatures</code><span></span></a></li>
<li><a href="#invalid_completion_signature" id="toc-invalid_completion_signature"><span class="toc-section-number">6.4</span>
<code class="sourceCode default">invalid_completion_signature</code><span></span></a></li>
<li><a href="#get_child_completion_signatures" id="toc-get_child_completion_signatures"><span class="toc-section-number">6.5</span>
<code class="sourceCode default">get_child_completion_signatures</code><span></span></a></li>
<li><a href="#completion-tag-comparison" id="toc-completion-tag-comparison"><span class="toc-section-number">6.6</span> Completion tag
comparison<span></span></a></li>
<li><a href="#eptr_completion_if" id="toc-eptr_completion_if"><span class="toc-section-number">6.7</span>
<code class="sourceCode default">eptr_completion_if</code><span></span></a></li>
</ul></li>
<li><a href="#questions-for-lewg" id="toc-questions-for-lewg"><span class="toc-section-number">7</span> Questions for
LEWG<span></span></a></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">8</span> Implementation
Experience<span></span></a></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">9</span> Proposed
Wording<span></span></a></li>
<li><a href="#proposed-wording-for-the-nice-to-haves" id="toc-proposed-wording-for-the-nice-to-haves"><span class="toc-section-number">10</span> Proposed Wording for the
Nice-to-haves<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">11</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">12</span> References<span></span></a></li>
</ul>
</div>
<div style="text-align: right;">
<p><em>“Only the exceptional paths bring exceptional glories!”</em><br />
— Mehmet Murat Ildan</p>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>The hardest part of writing a sender algorithm is often the
computation of its completion signatures, an intricate meta-programming
task. Using sender algorithms incorrectly leads to large,
incomprehensible errors deep within the completion-signatures
meta-program. What is needed is a way to propagate type errors
automatically to the API boundary where they can be reported concisely,
much the way exceptions do for runtime errors.</p>
<p>Support for exceptions during constant-evaluation was recently
accepted into the Working Draft for C++26. We can take advantage of this
powerful new feature to easily propagate type errors during the
computation of a sender’s completion signatures. This significantly
improves the diagnostics users are likely to encounter while also
simplifying the job of writing new sender algorithms.</p>
<h1 data-number="2" id="executive-summary"><span class="header-section-number">2</span> Executive Summary<a href="#executive-summary" class="self-link"></a></h1>
<p>This paper proposes the following changes to the working draft with
the addition of <span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span>. Subsequent
sections will address the motivation and the designs in detail.</p>
<ol type="1">
<li>Change <code class="sourceCode default">std::execution::get_completion_signatures</code>
from a customization point object that accepts a sender and (optionally)
an environment to a <code class="sourceCode default">consteval</code>
function template that takes no arguments, as follows:</li>
</ol>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>After</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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">inline</span> <span class="kw">constexpr</span> <span class="kw">struct</span> get_completion_signatures_t <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</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>Sndr<span class="op">&amp;&amp;</span>, Env<span class="op">&amp;&amp;...)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> get_completion_signatures <span class="op">{}</span>;</span></code></pre></div>

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

<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">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_completion_signatures<span class="op">()</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> <em><code class="sourceCode default">valid-completion-signatures</code></em> <span class="kw">auto</span>;</span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<ol start="2" type="1">
<li>Change the mechanism by which senders customize
<code class="sourceCode default">get_completion_signatures</code> from a
member function that accepts the <em>cv</em>-qualified sender object and
an optional environment object to a
<code class="sourceCode default">static constexpr</code> function
template that take the sender and environment types as template
parameters.</li>
</ol>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>After</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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> my_sender <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> <em><code class="sourceCode default">some-predicate</code></em><span class="op">&lt;</span>Self, Env<span class="op">...&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> get_completion_signatures<span class="op">(</span><span class="kw">this</span> Self<span class="op">&amp;&amp;</span>, Env<span class="op">&amp;&amp;)</span> <span class="op">{</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> completion_signatures<span class="op">&lt;</span><span class="co">/* … */</span><span class="op">&gt;()</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>

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

<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> my_sender <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> get_completion_signatures<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="cf">if</span> <span class="kw">constexpr</span> <span class="op">(!</span><em><code class="sourceCode default">some-predicate</code></em><span class="op">&lt;</span>Self, Env<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>      <span class="cf">throw</span> <em><code class="sourceCode default">a-helpful-diagnostic</code></em><span class="op">()</span>; <span class="co">// &lt;--- LOOK!</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> completion_signatures<span class="op">&lt;</span><span class="co">/* … */</span><span class="op">&gt;()</span>;</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">...</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<ol start="3" type="1">
<li>Change the
<code class="sourceCode default">sender_in&lt;Sender, Env...&gt;</code>
concept to test that <code class="sourceCode default">get_completion_signatures&lt;Sndr, Env...&gt;()</code>
is a constant expression.</li>
</ol>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>After</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> sender_in <span class="op">=</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  sender<span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>queryable<span class="op">&lt;</span>Env<span class="op">&gt;</span> <span class="op">&amp;&amp;...)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span>Sndr<span class="op">&amp;&amp;</span> sndr, Env<span class="op">&amp;&amp;...</span> env<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> get_completion_signatures<span class="op">(</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>forward<span class="op">&lt;</span>Sndr<span class="op">&gt;(</span>sndr<span class="op">)</span>,</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>forward<span class="op">&lt;</span>Env<span class="op">&gt;(</span>env<span class="op">)...)</span> <span class="op">}</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>            <span class="op">-&gt;</span> <em><code class="sourceCode default">valid-completion-signatures</code></em>;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span></code></pre></div>

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

<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">auto</span><span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em><code class="sourceCode default">is-constant</code></em> <span class="op">=</span> <span class="kw">true</span>; <span class="co">// exposition only</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> sender_in <span class="op">=</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  sender<span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span>queryable<span class="op">&lt;</span>Env<span class="op">&gt;</span> <span class="op">&amp;&amp;...)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  <em><code class="sourceCode default">is-constant</code></em><span class="op">&lt;</span>get_completion_signatures<span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;()&gt;</span>;</span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<ol start="4" type="1">
<li><p>In the exposition-only
<em><code class="sourceCode default">basic-sender</code></em> class
template, specify under what conditions its
<code class="sourceCode default">get_completion_signatures</code> static
member function is ill-formed when called without an
<code class="sourceCode default">Env</code> template parameter (see
proposed wording for details).</p></li>
<li><p>Add a <code class="sourceCode default">dependent_sender</code>
concept that is modeled by sender types that do not know how they will
complete independent of their execution environment.</p></li>
<li><p>[Optional]: Remove the
<code class="sourceCode default">transform_completion_signatures</code>
alias template.</p></li>
</ol>
<p>The following additions are suggested by this paper to make working
with completion signatures in
<code class="sourceCode default">constexpr</code> code easier. None of
these additions is strictly necessary.</p>
<ul>
<li><p>Extend the <a href="#completion_signatures"><code class="sourceCode default">completion_signatures</code></a>
class template with <code class="sourceCode default">constexpr</code>
operations that make the manipulation of completion signatures more
ergonomic. These extensions are:</p>
<ul>
<li><p>Combining two sets of completion signatures with
<code class="sourceCode default">operator+</code>.</p></li>
<li><p>Treating an instance of a completion signatures specialization as
a tuple of function pointers. For example, <code class="sourceCode default">completion_signatures&lt;set_value_t(int), set_stopped_t()&gt;{}</code>
would be usable as if it were <code class="sourceCode default">tuple&lt;set_value_t(*)(), set_stopped_t(*)()&gt;{nullptr, nullptr}</code>,
which makes <code class="sourceCode default">std::apply</code> useful
for munging completion signatures.</p></li>
<li><p>Adding CTAD to
<code class="sourceCode default">completion_signatures</code> to deduce
the signature types from a list of function pointers. Together with the
above item, the following is the identity transform, given a
<code class="sourceCode default">completion_signatures</code> object
<code class="sourceCode default">cs</code>:</p>
<blockquote>
<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> cs2 <span class="op">=</span> std<span class="op">::</span>apply<span class="op">([](</span><span class="kw">auto</span><span class="op">...</span> sigs<span class="op">){</span> <span class="cf">return</span> completion_signatures<span class="op">{</span>sigs<span class="op">...}</span>; <span class="op">}</span>, cs<span class="op">)</span>;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(^^</span><span class="kw">decltype</span><span class="op">(</span>cs<span class="op">)</span> <span class="op">==</span> <span class="op">^^</span><span class="kw">decltype</span><span class="op">(</span>cs2<span class="op">))</span>;</span></code></pre></div>
</blockquote></li>
</ul></li>
<li><p>Add a <a href="#make_completion_signatures"><code class="sourceCode default">make_completion_signatures</code></a>
helper function that takes signatures as template arguments or as
function arguments or both. The returned value would have signatures
that have been normalized, sorted (<span class="citation" data-cites="P2830R7">[<a href="#ref-P2830R7" role="doc-biblioref">P2830R7</a>]</span>), and made unique.</p></li>
<li><p>Add a <a href="#get_child_completion_signatures"><code class="sourceCode default">get_child_completion_signatures</code></a>
function template that makes it easy for a sender adaptor to get the
completion signatures of the child sender with the proper <em>cv</em>
qualification. It is simply:</p>
<blockquote>
<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">template</span> <span class="op">&lt;</span><span class="kw">class</span> Parent, <span class="kw">class</span> Child, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_child_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> CvChild <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>forward_like<span class="op">&lt;</span>Parent<span class="op">&gt;(</span>declval<span class="op">&lt;</span>Child<span class="op">&amp;&gt;()))</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> get_completion_signatures<span class="op">&lt;</span>CvChild, Env<span class="op">...&gt;()</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote></li>
<li><p>Reintroduce <a href="#transform_completion_signatures"><code class="sourceCode default">transform_completion_signatures</code></a>
as a <code class="sourceCode default">constexpr</code> function template
that accepts lambdas as transforms. For example, the following code
removes all error completions from a set,
<code class="sourceCode default">cs</code>:</p>
<blockquote>
<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">auto</span> cs2 <span class="op">=</span> transform_completion_signatures<span class="op">(</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  cs,</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">{}</span>, <span class="co">// accept the default value completion transform</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">[]&lt;</span><span class="kw">class</span> Error<span class="op">&gt;()</span> <span class="op">{</span> <span class="cf">return</span> completion_signatures<span class="op">{}</span>; <span class="op">})</span>;</span></code></pre></div>
</blockquote>
<p>See <a href="#transform_completion_signatures"><code class="sourceCode default">transform_completion_signatures</code></a>
for a design description and reference implementation of the
<code class="sourceCode default">transform_completion_signatures</code>
function template.</p></li>
<li><p>Add an <a href="#invalid_completion_signature"><code class="sourceCode default">invalid_completion_signature</code></a>
<code class="sourceCode default">consteval</code> function template
whose return type is
<code class="sourceCode default">completion_signatures&lt;&gt;</code>
but that throws an unspecified exception type that contains diagnostic
information. A typical use would look like this:</p>
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span> Env<span class="op">&gt;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> read_env_sender<span class="op">&lt;</span>Q<span class="op">&gt;::</span>get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">namespace</span> exec <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb10-5"><a href="#cb10-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>invocable<span class="op">&lt;</span>Q, Env<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// return type deduced to be completion_signatures&lt;&gt; but function exits</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">// with an exception that contains the relevant diagnostic information.</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> exec<span class="op">::</span>invalid_completion_signature<span class="op">&lt;</span></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>       _IN_ALGORITHM<span class="op">&lt;</span>read_env<span class="op">&gt;</span>,</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>       _WITH_QUERY<span class="op">(</span>Q<span class="op">)</span>,</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>       _WITH_ENVIRONMENT<span class="op">(</span>Env<span class="op">)</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;(</span><span class="st">&quot;The environment does not provide a value for the given query type.&quot;</span><span class="op">)</span>;</span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb10-14"><a href="#cb10-14" 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>Q, Env<span class="op">&gt;</span>;</span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> exec<span class="op">::</span>completion_signatures<span class="op">&lt;</span>exec<span class="op">::</span>set_value_t<span class="op">(</span>Result<span class="op">)&gt;()</span>;</span>
<span id="cb10-16"><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-17"><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote></li>
</ul>
<h1 data-number="3" id="revision-history"><span class="header-section-number">3</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<h2 data-number="3.1" id="r0"><span class="header-section-number">3.1</span> R0<a href="#r0" class="self-link"></a></h2>
<ul>
<li>Initial revision</li>
</ul>
<h1 data-number="4" id="motivation"><span class="header-section-number">4</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>This paper exists principly to improve the experience of users who
make type errors in their sender expressions by leveraging exceptions
during constant- evaluation. It is a follow-on of <span class="citation" data-cites="P3164R2">[<a href="#ref-P3164R2" role="doc-biblioref">P3164R2</a>]</span>, which defines a category of
“non-dependent” senders that can and must be type-checked early.</p>
<p>Senders have a construction phase and a subsequent connection phase.
Prior to P3164, all type-checking of senders happened at the connection
phase (when a sender is connected to a receiver). P3164 mandates that
the sender algorithms type-check non-dependent senders, moving the
diagnostic closer to the source of the error.</p>
<p>This paper addresses the <em>quality</em> of those diagnostics and
the diagnostics users encounter when a dependent sender fails
type-checking at connection time.</p>
<p>Senders are expression trees, and type errors can happen deep within
their structure. If programmed naively, ill-formed senders would
generate megabytes of incomprehensible diagnostics. The challenge is to
report type errors <em>concisely</em> and <em>comprehensibly</em>, at
the right level of abstraction.</p>
<p>Doing this requires propagating domain-specific descriptions of type
errors out of the completion signatures meta-program so they can be
reported concisely. Such error detection and propagation is very
cumbersome in template meta-programming.</p>
<p>The C++ solution to error propagation is exceptions. With the
adoption of <span class="citation" data-cites="P3068R6">[<a href="#ref-P3068R6" role="doc-biblioref">P3068R6</a>]</span>, C++26 has
gained the ability to throw and catch exceptions during
constant-evaluation. If we express the computation of completion
signatures as a <code class="sourceCode default">constexpr</code>
meta-program, we can use exceptions to propagate type errors. This
greatly improves diagnostics and even simplifies the code that computes
completion signatures.</p>
<p>This paper proposes changes to
<code class="sourceCode default">std::execution</code> that make the
computation of a sender’s completion signatures an evaluation of a
<code class="sourceCode default">constexpr</code> function. It also
specifies the conditions under which the computation is to exit with an
exception.</p>
<h1 data-number="5" id="proposed-design-necessary-changes"><span class="header-section-number">5</span> Proposed Design, Necessary
Changes<a href="#proposed-design-necessary-changes" class="self-link"></a></h1>
<h2 data-number="5.1" id="get_completion_signatures"><span class="header-section-number">5.1</span>
<code class="sourceCode default">get_completion_signatures</code><a href="#get_completion_signatures" class="self-link"></a></h2>
<p>In the Working Draft, a sender’s completion signatures are determined
by the type of the expression <code class="sourceCode default">std::execution::get_completion_signatures(sndr, env)</code>
(or, after P3164, <code class="sourceCode default">std::execution::get_completion_signatures(sndr)</code>
for non-dependent senders). Only the type of the expression matters; the
expression itself is never evaluated.</p>
<p>In the design proposed by this paper, the
<code class="sourceCode default">get_completion_signatures</code>
expression must be constant-evaluated in order use exceptions to report
errors. To make it ammenable to constant evaluation, it must not accept
arguments with runtime values, so the expression is changed to <code class="sourceCode default">std::execution::get_completion_signatures&lt;Sndr, Env...&gt;()</code>,
where <code class="sourceCode default">get_completion_signatures</code>
is a <code class="sourceCode default">consteval</code> function.</p>
<p>If an unhandled exception propagates out of
<code class="sourceCode default">get_completion_signatures</code> the
program is ill-formed (because
<code class="sourceCode default">get_completion_signatures</code> is
<code class="sourceCode default">consteval</code>). The diagnostic
displays the type and value of the exception.</p>
<p><code class="sourceCode default">std::execution::get_completion_signatures&lt;Sndr, Env...&gt;()</code>
in turn calls <code>remove_reference_t&lt;Sndr&gt;::template
get_completion_signatures&lt;Sndr, Env...&gt;()</code>, which computes
the completion signatures or throws as appropriate, as shown below:</p>
<blockquote>
<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="kw">namespace</span> exec <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> void_sender <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> sender_concept <span class="op">=</span> exec<span class="op">::</span>sender_t;</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> exec<span class="op">::</span>completion_signatures<span class="op">&lt;</span>exec<span class="op">::</span>set_value_t<span class="op">()&gt;()</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* … more … */</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>To better support the
<code class="sourceCode default">constexpr</code> value-oriented
programming style, calls to
<code class="sourceCode default">get_completion_signatures</code> from a
<code class="sourceCode default">constexpr</code> function are never
ill-formed, and they always have a
<code class="sourceCode default">completion_signatures</code> type.
<code class="sourceCode default">get_completion_signatures</code>
reports errors by failing to be a constant expression.</p>
<h3 data-number="5.1.1" id="non-non-dependent-senders"><span class="header-section-number">5.1.1</span> Non-non-dependent senders<a href="#non-non-dependent-senders" class="self-link"></a></h3>
<p><span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span> introduces the concept of
non-dependent senders: senders that have the same completion signatures
regardless of the receiver’s execution environment. For a sender type
<code class="sourceCode default">DependentSndr</code> whose completions
<em>do</em> depend on the environment, what should happen when the
sender’s completions are queried without an environment? That is, what
should the semantics be for <code class="sourceCode default">get_completion_signatures&lt;DependentSndr&gt;()</code>?</p>
<p><code class="sourceCode default">get_completion_signatures&lt;DependentSndr&gt;()</code>
should follow the general rule: it should be well-formed in a
<code class="sourceCode default">constexpr</code> function, and it
should have a
<code class="sourceCode default">completion_signatures</code> type. That
way, sender adaptors do not need to do anything special when computing
the completions of child senders that are dependent. So <code class="sourceCode default">get_completion_signatures&lt;DependentSndr&gt;()</code>
should throw.</p>
<p>If <code class="sourceCode default">get_completion_signatures&lt;Sndr&gt;()</code>
throws for dependent senders, and it also throws for non-dependent
senders that fail to type-check, how then do we distinguish between
valid dependent and invalid non-dependent senders? We can distinguish by
checking the type of the exception.</p>
<p>An example will help. Consider the
<code class="sourceCode default">read_env(q)</code> sender, a dependent
sender that sends the result of calling
<code class="sourceCode default">q</code> with the receiver’s
environment. It cannot compute its completion signatures without an
environment. The natural way for the
<code class="sourceCode default">read_env</code> sender to express that
is to require an <code class="sourceCode default">Env</code> parameter
to its customization of
<code class="sourceCode default">get_completion_signatures</code>:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> exec <span class="op">=</span> std<span class="op">::</span>execution;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Query<span class="op">&gt;</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> read_env_sender <span class="op">{</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> sender_concept <span class="op">=</span> exec<span class="op">::</span>sender_t;</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span> Env<span class="op">&gt;</span> <span class="co">// </span><span class="al">NOTE</span><span class="co">: Env is not optional!</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-9"><a href="#cb12-9" 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>invocable<span class="op">&lt;</span>Query, Env<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>      <span class="cf">throw</span> <em><code class="sourceCode default">exception-type-goes-here</code></em><span class="op">()</span>;</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-12"><a href="#cb12-12" 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>Query, Env<span class="op">&gt;</span>;</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> exec<span class="op">::</span>completion_signatures<span class="op">&lt;</span>exec<span class="op">::</span>set_value_t<span class="op">(</span>Result<span class="op">)&gt;()</span>;</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* … more … */</span></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>That makes <code class="sourceCode default">read_env_sender&lt;Q&gt;::get_completion_signatures&lt;Sndr&gt;()</code>
an ill-formed expression, which the
<code class="sourceCode default">get_completion_signatures</code>
function can detect. In such cases, it would throw an exception of a
special type that it can catch later when distinguishing between
dependent and non-dependent senders.</p>
<h3 data-number="5.1.2" id="implementation"><span class="header-section-number">5.1.2</span> Implementation<a href="#implementation" class="self-link"></a></h3>
<p>Since the design has several parts, reading the implementation of
<code class="sourceCode default">get_completion_signatures</code> is
probably the easiest way to understand it. The implementation is shown
below with comments describing the parts.</p>
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Some exposition-only helpers:</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...&gt;</span> <span class="kw">class</span> C, <span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em><code class="sourceCode default">well-formed-type</code></em> <span class="op">=</span>  <span class="co">// exposition only</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> C<span class="op">&lt;</span>Ts<span class="op">...&gt;</span>; <span class="op">}</span>;</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em><code class="sourceCode default">completion-signatures-of</code></em> <span class="op">=</span>  <span class="co">// exposition only</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">decltype</span><span class="op">(</span>remove_reference_t<span class="op">&lt;</span>Sndr<span class="op">&gt;::</span><span class="kw">template</span> get_completion_signatures<span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;())</span>;</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="co">// A sender is dependent when its get_completion_signatures customization</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="co">// cannot be called without an environment parameter.</span></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em><code class="sourceCode default">dependent-sender-without-env</code></em> <span class="op">=</span>  <span class="co">// exposition only</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">(</span><span class="kw">sizeof</span><span class="op">...(</span>Env<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">!</span><em><code class="sourceCode default">well-formed-type</code></em><span class="op">&lt;</span><em><code class="sourceCode default">completion-signatures-of</code></em>, Sndr<span class="op">&gt;</span>;</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>completion_signatures<span class="op">&gt;</span></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em><code class="sourceCode default">has-constexpr-completions-helper</code></em> <span class="op">=</span> <span class="kw">true</span>; <span class="co">// exposition only</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a><span class="co">// A concept that tests that a sender&#39;s customization of get_completion_signatures</span></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="co">// is well-formed, a constant expression, and has a type that is a specialization</span></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a><span class="co">// of completion_signatures&lt;&gt;.</span></span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> <em><code class="sourceCode default">has-constexpr-completions</code></em> <span class="op">=</span>   <span class="co">// exposition only</span></span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>  <em><code class="sourceCode default">has-constexpr-completions-helper</code></em><span class="op">&lt;</span></span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a>    remove_reference_t<span class="op">&lt;</span>Sndr<span class="op">&gt;::</span><span class="kw">template</span> get_completion_signatures<span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;()&gt;</span>;</span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a><span class="co">// This is a special exception type that will be thrown by</span></span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a><span class="co">// std::execution::get_completion_signatures when trying to query a dependent</span></span>
<span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a><span class="co">// sender for its non-dependent completions.</span></span>
<span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em><code class="sourceCode default">dependent-sender-error</code></em> <span class="op">{</span> <span class="op">}</span>;  <span class="co">// exposition only</span></span>
<span id="cb13-32"><a href="#cb13-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-33"><a href="#cb13-33" aria-hidden="true" tabindex="-1"></a><span class="co">// Given a sender and zero or one environment, compute the sender&#39;s completion</span></span>
<span id="cb13-34"><a href="#cb13-34" aria-hidden="true" tabindex="-1"></a><span class="co">// signatures. Calls to this function are always well-formed and have a type</span></span>
<span id="cb13-35"><a href="#cb13-35" aria-hidden="true" tabindex="-1"></a><span class="co">// that is a specialization of completion_signatures.</span></span>
<span id="cb13-36"><a href="#cb13-36" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb13-37"><a href="#cb13-37" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-completion-signatures-impl</code></em><span class="op">()</span> <span class="op">{</span></span>
<span id="cb13-38"><a href="#cb13-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em><code class="sourceCode default">sndr-type</code></em> <span class="op">=</span> remove_reference_t<span class="op">&lt;</span>Sndr<span class="op">&gt;</span>;</span>
<span id="cb13-39"><a href="#cb13-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-40"><a href="#cb13-40" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><em><code class="sourceCode default">has-constexpr-completions</code></em><span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb13-41"><a href="#cb13-41" aria-hidden="true" tabindex="-1"></a>    <span class="co">// In the happy case where Sndr&#39;s customization is well-formed, a constant</span></span>
<span id="cb13-42"><a href="#cb13-42" aria-hidden="true" tabindex="-1"></a>    <span class="co">// expression, and has a completion_signatures&lt;&gt; type, just return the</span></span>
<span id="cb13-43"><a href="#cb13-43" aria-hidden="true" tabindex="-1"></a>    <span class="co">// result of calling the customization.</span></span>
<span id="cb13-44"><a href="#cb13-44" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <em><code class="sourceCode default">sndr-type</code></em><span class="op">::</span><span class="kw">template</span> get_completion_signatures<span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;()</span>;</span>
<span id="cb13-45"><a href="#cb13-45" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-46"><a href="#cb13-46" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><em><code class="sourceCode default">dependent-sender-without-env</code></em><span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb13-47"><a href="#cb13-47" aria-hidden="true" tabindex="-1"></a>    <span class="co">// If Sndr is dependent and we don&#39;t have an environment, throw an exception,</span></span>
<span id="cb13-48"><a href="#cb13-48" aria-hidden="true" tabindex="-1"></a>    <span class="co">// but ensure that the return type of this function is a specialization</span></span>
<span id="cb13-49"><a href="#cb13-49" aria-hidden="true" tabindex="-1"></a>    <span class="co">// of completion_signatures.</span></span>
<span id="cb13-50"><a href="#cb13-50" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span><span class="cf">throw</span> <em><code class="sourceCode default">dependent-sender-error</code></em><span class="op">()</span>, completion_signatures<span class="op">())</span>;</span>
<span id="cb13-51"><a href="#cb13-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-52"><a href="#cb13-52" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(!</span><em><code class="sourceCode default">well-formed-type</code></em><span class="op">&lt;</span><em><code class="sourceCode default">completion-signatures-of</code></em>, Sndr, Env<span class="op">...&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb13-53"><a href="#cb13-53" aria-hidden="true" tabindex="-1"></a>    <span class="co">// For some reason, the Sndr&#39;s customization cannot be called even with an</span></span>
<span id="cb13-54"><a href="#cb13-54" aria-hidden="true" tabindex="-1"></a>    <span class="co">// environment. This is a library bug; it should always be callable from</span></span>
<span id="cb13-55"><a href="#cb13-55" aria-hidden="true" tabindex="-1"></a>    <span class="co">// a constexpr context. Report the library bug by throwing an exception,</span></span>
<span id="cb13-56"><a href="#cb13-56" aria-hidden="true" tabindex="-1"></a>    <span class="co">// taking care to ensure the return type is a completion_signatures type.</span></span>
<span id="cb13-57"><a href="#cb13-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span><span class="cf">throw</span> <em><code class="sourceCode default">unspecified</code></em>, completion_signatures<span class="op">())</span>;</span>
<span id="cb13-58"><a href="#cb13-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-59"><a href="#cb13-59" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb13-60"><a href="#cb13-60" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Otherwise, we reach here under the following conditions:</span></span>
<span id="cb13-61"><a href="#cb13-61" aria-hidden="true" tabindex="-1"></a>    <span class="co">// - The call to Sndr&#39;s customization cannot be constant-evaluated (possibly</span></span>
<span id="cb13-62"><a href="#cb13-62" aria-hidden="true" tabindex="-1"></a>    <span class="co">//   because it throws), or</span></span>
<span id="cb13-63"><a href="#cb13-63" aria-hidden="true" tabindex="-1"></a>    <span class="co">// - Its return type is not a completion_signatures type.</span></span>
<span id="cb13-64"><a href="#cb13-64" aria-hidden="true" tabindex="-1"></a>    <span class="co">//</span></span>
<span id="cb13-65"><a href="#cb13-65" aria-hidden="true" tabindex="-1"></a>    <span class="co">// We want to call the call the Sndr&#39;s customization so that if it throws</span></span>
<span id="cb13-66"><a href="#cb13-66" aria-hidden="true" tabindex="-1"></a>    <span class="co">// an exception, that exception&#39;s information will appear in the diagnostic.</span></span>
<span id="cb13-67"><a href="#cb13-67" aria-hidden="true" tabindex="-1"></a>    <span class="co">// If it doesn&#39;t throw, _we_ should throw to let the developer know that</span></span>
<span id="cb13-68"><a href="#cb13-68" aria-hidden="true" tabindex="-1"></a>    <span class="co">// their customization returned an invalid type. And again, ensure that</span></span>
<span id="cb13-69"><a href="#cb13-69" aria-hidden="true" tabindex="-1"></a>    <span class="co">// the return type is a completion_signatures type.</span></span>
<span id="cb13-70"><a href="#cb13-70" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span><em><code class="sourceCode default">sndr-type</code></em><span class="op">::</span><span class="kw">template</span> get_completion_signatures<span class="op">&lt;</span>Sndr, Env<span class="op">...&gt;()</span>,</span>
<span id="cb13-71"><a href="#cb13-71" aria-hidden="true" tabindex="-1"></a>            <span class="cf">throw</span> <em><code class="sourceCode default">unspecified</code></em>,</span>
<span id="cb13-72"><a href="#cb13-72" aria-hidden="true" tabindex="-1"></a>            completion_signatures<span class="op">())</span>;</span>
<span id="cb13-73"><a href="#cb13-73" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-74"><a href="#cb13-74" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb13-75"><a href="#cb13-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-76"><a href="#cb13-76" aria-hidden="true" tabindex="-1"></a><span class="co">// Applies a late sender transformation if appropriate, then computes the</span></span>
<span id="cb13-77"><a href="#cb13-77" aria-hidden="true" tabindex="-1"></a><span class="co">// completion signatures. Calls to this function are always well-formed and</span></span>
<span id="cb13-78"><a href="#cb13-78" aria-hidden="true" tabindex="-1"></a><span class="co">// have a type that is a specialization of completion_signatures.</span></span>
<span id="cb13-79"><a href="#cb13-79" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb13-80"><a href="#cb13-80" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb13-81"><a href="#cb13-81" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">...(</span>Env<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-82"><a href="#cb13-82" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <em><code class="sourceCode default">get-completion-signatures-impl</code></em><span class="op">&lt;</span>Sndr<span class="op">&gt;()</span>;</span>
<span id="cb13-83"><a href="#cb13-83" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-84"><a href="#cb13-84" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb13-85"><a href="#cb13-85" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Apply a late sender transform:</span></span>
<span id="cb13-86"><a href="#cb13-86" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> NewSndr <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>transform_sender<span class="op">(</span><span class="co">/* … */</span><span class="op">))</span>;</span>
<span id="cb13-87"><a href="#cb13-87" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <em><code class="sourceCode default">get-completion-signatures-impl</code></em><span class="op">&lt;</span>NewSndr, Env<span class="op">...&gt;()</span>;</span>
<span id="cb13-88"><a href="#cb13-88" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-89"><a href="#cb13-89" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Given this definition of
<code class="sourceCode default">get_completion_signatures</code>, we
can implement a <code class="sourceCode default">dependent_sender</code>
concept as follows:</p>
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Returns true when get_completion_signatures&lt;Sndr&gt;() throws a</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="co">// dependent-sender-error. Returns false when</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="co">// get_completion_signatures&lt;Sndr&gt;() returns normally (Sndr is non-dependent),</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="co">// or when it throws any other kind of exception (Sndr fails type-checking).</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="dt">bool</span> <em><code class="sourceCode default">is-dependent-sender-helper</code></em><span class="op">()</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>    get_completion_signatures<span class="op">&lt;</span>Sndr<span class="op">&gt;()</span>;</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">catch</span> <span class="op">(</span><em><code class="sourceCode default">dependent-sender-error</code></em><span class="op">&amp;)</span> <span class="op">{</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">true</span>;</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> dependent_sender <span class="op">=</span></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>  sender<span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> std<span class="op">::</span>bool_constant<span class="op">&lt;</span><em><code class="sourceCode default">is-dependent-sender-helper</code></em><span class="op">&lt;</span>Sndr<span class="op">&gt;()&gt;::</span>value;</span></code></pre></div>
</blockquote>
<p>After the adoption of <span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span>, the sender
algorithms are all required to return senders that are either dependent
or else that type-check successfully. One way to implement this is with
the following helper:</p>
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> __type_check_sender<span class="op">(</span>Sndr sndr<span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(!</span>dependent_sender<span class="op">&lt;</span>Sndr<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    <span class="co">// This line will fail to compile if Sndr fails its type checking. We</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">// don&#39;t want to perform this type checking when Sndr is dependent, though.</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Without an environment, the sender doesn&#39;t know its completions.</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    get_completion_signatures<span class="op">&lt;</span>Sndr<span class="op">&gt;()</span>;</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> sndr;</span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Sender algorithms could use this helper when returning the new
sender. For example, the <code class="sourceCode default">then</code>
algorithm might look something like this:</p>
<blockquote>
<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">inline</span> <span class="kw">constexpr</span> <span class="kw">struct</span> then_t <span class="op">:</span> __pipeable_sender_adaptor<span class="op">&lt;</span>then_t<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span>sender Sndr, <span class="kw">class</span> Fn<span class="op">&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>Sndr sndr, Fn fn<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> __type_check_sender<span class="op">(</span>__then_sender<span class="op">{</span>std<span class="op">::</span>move<span class="op">(</span>sndr<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>fn<span class="op">)})</span>;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> then <span class="op">{}</span>;</span></code></pre></div>
</blockquote>
<h2 data-number="5.2" id="sender_in"><span class="header-section-number">5.2</span>
<code class="sourceCode default">sender_in</code><a href="#sender_in" class="self-link"></a></h2>
<p>With the above changes, we need to tweak the
<code class="sourceCode default">sender_in</code> concept to require
that <code class="sourceCode default">get_completion_signatures&lt;Sndr, Env...&gt;()</code>
is a constant expression.</p>
<p>The changes to <code class="sourceCode default">sender_in</code>
relative to <span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span> are as
follows:</p>
<blockquote>
<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="add" style="color: #006e28"><ins><span><code class="sourceCode default">template &lt;auto&gt;</code></span></ins></span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">concept <em>is-constant</em> = true; <em>// exposition only</em></code></span></ins></span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> sender_in <span class="op">=</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>    sender<span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span><span class="kw">sizeof</span><span class="op">...(</span>Env<span class="op">)</span> <span class="op">&lt;=</span> <span class="dv">1</span><span class="op">)</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">(</span>queryable<span class="op">&lt;</span>Env<span class="op">&gt;</span> <span class="op">&amp;&amp;...)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em>is-constant</em>&lt;get_completion_signatures&lt;Sndr, Env...&gt;()&gt;;</code></span></ins></span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">requires (Sndr&amp;&amp; sndr, Env&amp;&amp;... env) {</code></span></del></span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">{ get_completion_signatures(std::forward&lt;Sndr&gt;(sndr), std::forward&lt;Env&gt;(env)...) }</code></span></del></span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>        <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">-&gt; <em>valid-completion-signatures</em>;</code></span></del></span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">};</code></span></del></span></span></code></pre></div>
</blockquote>
<h2 data-number="5.3" id="basic-sender"><span class="header-section-number">5.3</span>
<em><code class="sourceCode default">basic-sender</code></em><a href="#basic-sender" class="self-link"></a></h2>
<p>The sender algorithms are expressed in terms of the exposition-only
class template
<em><code class="sourceCode default">basic-sender</code></em>. The
mechanics of computing completion signatures is not specified, however,
so very little change there is needed to implement this proposal.</p>
<p>We do, however, have to say when
<code><em>basic-sender</em>::get_completion_signatures&lt;Sndr&gt;()</code>
is ill-formed. In <span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span>,
non-dependent senders are dealt with by discussing whether or not a
sender’s potentially-evaluated completion operations are dependent on
the type of the receiver’s environment. In this paper, we make a similar
appeal when specifying whether or not
<code><em>basic-sender</em>::get_completion_signatures&lt;Sndr&gt;()</code>
is well-formed.</p>
<h2 data-number="5.4" id="dependent_sender"><span class="header-section-number">5.4</span>
<code class="sourceCode default">dependent_sender</code><a href="#dependent_sender" class="self-link"></a></h2>
<p>Users who write their own sender adaptors will also want to perform
early type-checking of senders that are not dependent. Therefore, they
need a way to determine whether or not a sender is dependent.</p>
<p>In the section <a href="#get_completion_signatures"><code class="sourceCode default">get_completion_signatures</code></a>
we show how the concept
<code class="sourceCode default">dependent_sender</code> can be
implemented in terms of this paper’s
<code class="sourceCode default">get_completion_signatures</code>
function template. By making this a public-facing concept, we give
sender adaptor authors a way to do early type-checking, just like the
standard adaptors.</p>
<h1 data-number="6" id="proposed-design-nice-to-haves"><span class="header-section-number">6</span> Proposed Design, Nice-to-haves<a href="#proposed-design-nice-to-haves" class="self-link"></a></h1>
<h2 data-number="6.1" id="completion_signatures"><span class="header-section-number">6.1</span>
<code class="sourceCode default">completion_signatures</code><a href="#completion_signatures" class="self-link"></a></h2>
<p>Computing completions signatures is now to be done using
<code class="sourceCode default">constexpr</code> meta-programming by
manipulating values using ordinary imperative C++ rather than template
meta-programming. To better support this style of programming, it is
helpful to add <code class="sourceCode default">constexpr</code>
operations that manipulate instances of specializations of the
<code class="sourceCode default">completion_signatures</code> class
template.</p>
<p>For example, it should be possible to take the union of two sets of
completion signatures. <code class="sourceCode default">operator+</code>
seems like a natural choice for that:</p>
<blockquote>
<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>completion_signatures<span class="op">&lt;</span>set_value_t<span class="op">(</span><span class="dt">int</span><span class="op">)</span>, set_error_t<span class="op">(</span>exception_ptr<span class="op">)&gt;</span> cs1;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>completion_signatures<span class="op">&lt;</span>set_stopped_t<span class="op">()</span>, set_error_t<span class="op">(</span>exception_ptr<span class="op">)&gt;</span> cs2;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> cs3 <span class="op">=</span> cs1 <span class="op">+</span> cs2; <span class="co">// completion_signatures&lt;set_value_t(int),</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>                      <span class="co">//                       set_error_t(exception_ptr),</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>                      <span class="co">//                       set_stopped_t()&gt;</span></span></code></pre></div>
</blockquote>
<p>It can also be convenient for
<code class="sourceCode default">completion_signature</code>
specializations to model <a href="https://en.cppreference.com/w/cpp/utility/tuple/tuple-like"><em><code class="sourceCode default">tuple-like</code></em></a>.
Although tuple elements cannot have funtion type, they can have function
<em>pointer</em> type. With this proposal, an object like <code class="sourceCode default">completion_signatures&lt;set_value_t(int), set_stopped_t()&gt;{}</code>
behaves like <code class="sourceCode default">tuple&lt;set_value_t(*)(int), set_stopped_t(*)()&gt;{nullptr, nullptr}</code>
(except that it wouldn’t actually have to store the
<code class="sourceCode default">nullptr</code>s). That would make it
possible to manipulate completion signatures using
<code class="sourceCode default">std::apply</code>:</p>
<blockquote>
<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">auto</span> cs <span class="op">=</span> <span class="co">/* … */</span>;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="co">// Add an lvalue reference to all arguments of all signatures:</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> add_ref <span class="op">=</span>     <span class="op">[]&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;(</span>T<span class="op">(*)(</span>As<span class="op">...))</span> <span class="op">-&gt;</span> T<span class="op">(*)(</span>As<span class="op">&amp;...)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span>;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> add_ref_all <span class="op">=</span> <span class="op">[=](</span><span class="kw">auto</span><span class="op">...</span> sigs<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> make_completion_signatures<span class="op">(</span>add_ref<span class="op">(</span>sigs<span class="op">)...)</span>; <span class="op">}</span>;</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> std<span class="op">::</span>apply<span class="op">(</span>add_ref_all, cs<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>The code above uses another nice-to-have feature: a
<code class="sourceCode default">make_completion_signatures</code>
helper function that deduces the signatures from the arguments, removes
any duplicates, and returns a new instance of
<code class="sourceCode default">completion_signatures</code>.</p>
<p>Consider trying to do all the above using template meta-programming.
😬</p>
<h2 data-number="6.2" id="make_completion_signatures"><span class="header-section-number">6.2</span>
<code class="sourceCode default">make_completion_signatures</code><a href="#make_completion_signatures" class="self-link"></a></h2>
<p>The
<code class="sourceCode default">make_completion_signatures</code>
helper function described just above would allow users to build a
<code class="sourceCode default">completion_signatures</code> object
from a bunch of signature types, or from function pointer objects, or a
combination of both:</p>
<blockquote>
<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="co">// Returns a default-initialized object of type completion_signatures&lt;Sigs...&gt;,</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="co">// where Sigs is the set union of the normalized ExplicitSigs and DeducedSigs.</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><em><code class="sourceCode default">completion-signature</code></em><span class="op">...</span> ExplicitSigs, <em><code class="sourceCode default">completion-signature</code></em><span class="op">...</span> DeducedSigs<span class="op">&gt;</span></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> make_completion_signatures<span class="op">(</span>DeducedSigs<span class="op">*...</span> sigs<span class="op">)</span> <span class="kw">noexcept</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> <em><code class="sourceCode default">valid-completion-signatures</code></em> <span class="kw">auto</span>;</span></code></pre></div>
</blockquote>
<p>To “normalize” a completion signature means to strip rvalue
references from the arguments. So, <code class="sourceCode default">set_value_t(int&amp;&amp;, float&amp;)</code>
becomes
<code class="sourceCode default">set_value_t(int, float&amp;)</code>.
<code class="sourceCode default">make_completions_signatures</code>
first normalizes all the signatures and then removes duplicates. (<span class="citation" data-cites="P2830R7">[<a href="#ref-P2830R7" role="doc-biblioref">P2830R7</a>]</span> lets us order types, so making
the set unique will be <em>O</em>(<em>n</em> log <em>n</em>).)</p>
<h2 data-number="6.3" id="transform_completion_signatures"><span class="header-section-number">6.3</span>
<code class="sourceCode default">transform_completion_signatures</code><a href="#transform_completion_signatures" class="self-link"></a></h2>
<p>The current Working Draft has a utility to make type transformations
of completion signature sets simpler: the alias template
<code class="sourceCode default">transform_completion_signatures</code>.
It looks like this:</p>
<blockquote>
<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="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>value-transform-default</em> <span class="op">=</span> completion_signatures<span class="op">&lt;</span>set_value_t<span class="op">(</span>As<span class="op">...)&gt;</span>;</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Error<span class="op">&gt;</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>error-transform-default</em> <span class="op">=</span> completion_signatures<span class="op">&lt;</span>set_error_t<span class="op">(</span>Error<span class="op">)&gt;</span>;</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><em>valid-completion-signatures</em> Completions,</span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>          <em>valid-completion-signatures</em> OtherCompletions <span class="op">=</span> completion_signatures<span class="op">&lt;&gt;</span>,</span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>          <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...&gt;</span> <span class="kw">class</span> ValueTransform <span class="op">=</span> <em>value-transform-default</em>,</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>          <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">class</span> ErrorTransform <span class="op">=</span> <em>error-transform-default</em>,</span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>          <em>valid-completion-signatures</em> StoppedCompletions <span class="op">=</span> completion_signatures<span class="op">&lt;</span>set_stopped_t<span class="op">()&gt;&gt;</span></span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> transform_completion_signatures <span class="op">=</span> <span class="co">/*see below*/</span>;</span></code></pre></div>
</blockquote>
<p>Anything that can be done with
<code class="sourceCode default">transform_completion_signatures</code>
can be done in <code class="sourceCode default">constexpr</code> using
<code class="sourceCode default">std::apply</code>, a lambda with
<code class="sourceCode default">if constexpr</code>, and
<code class="sourceCode default">operator+</code> of
<code class="sourceCode default">completion_signature</code> objects. In
fact, we could even implement
<code class="sourceCode default">transform_completion_signatures</code>
itself that way:</p>
<blockquote>
<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="kw">template</span> <span class="op">&lt;</span><span class="co">/* … as before … */</span><span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> transform_completion_signatures <span class="op">=</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>constant_wrapper<span class="op">&lt;</span> <span class="co">// see <span class="citation" data-cites="P2781R5">[@P2781R5]</span></span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>apply<span class="op">(</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">[](</span><span class="kw">auto</span><span class="op">...</span> sigs<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">([]&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;(</span>T <span class="op">(*)(</span>As<span class="op">...))</span> <span class="op">{</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>          <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(^^</span>T <span class="op">==</span> <span class="op">^^</span>set_value_t<span class="op">)</span> <span class="op">{</span> <span class="co">// use reflection to test type equality</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> ValueTransform<span class="op">&lt;</span>As<span class="op">...&gt;()</span>;</span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(^^</span>T <span class="op">==</span> <span class="op">^^</span>set_error_t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> ErrorTransform<span class="op">&lt;</span>As<span class="op">...[</span><span class="dv">0</span><span class="op">]&gt;()</span>;</span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> StoppedCompletions<span class="op">()</span>;</span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">}(</span>sigs<span class="op">)</span> <span class="op">+...+</span> completion_signatures<span class="op">())</span>;</span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span>,</span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a>      Completions<span class="op">()</span></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span> <span class="op">+</span> OtherCompletions<span class="op">()</span></span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">&gt;::</span>value_type;</span></code></pre></div>
</blockquote>
<p>This paper proposes dropping the
<code class="sourceCode default">transform_completion_signatures</code>
type alias since it is not in the ideal form for
<code class="sourceCode default">constexpr</code> meta-programming, and
since <code class="sourceCode default">std::apply</code> is good enough
(sort of).</p>
<p>However, should we decide to keep the functionality of
<code class="sourceCode default">transform_completion_signatures</code>,
we can reexpress it as a
<code class="sourceCode default">constexpr</code> function that accepts
transforms as lambdas:</p>
<blockquote>
<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">constexpr</span> <span class="kw">auto</span> <em>value-transform-default</em> <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;()</span> <span class="op">{</span> <span class="cf">return</span> completion_signatures<span class="op">&lt;</span>set_value_t<span class="op">(</span>As<span class="op">...)&gt;()</span>; <span class="op">}</span>;</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <em>error-transform-default</em> <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">class</span> Error<span class="op">&gt;()</span> <span class="op">{</span> <span class="cf">return</span> completion_signatures<span class="op">&lt;</span>set_error_t<span class="op">(</span>Error<span class="op">)&gt;()</span>; <span class="op">}</span>;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><em>valid-completion-signatures</em> Completions,</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> ValueTransform <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span><em>value-transform-default</em><span class="op">)</span>,</span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> ErrorTransform <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span><em>error-transform-default</em><span class="op">)</span>,</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>          <em>valid-completion-signatures</em> StoppedCompletions <span class="op">=</span> completion_signatures<span class="op">&lt;</span>set_stopped_t<span class="op">()&gt;</span>,</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>          <em>valid-completion-signatures</em> OtherCompletions <span class="op">=</span> completion_signatures<span class="op">&lt;&gt;&gt;</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> transform_completion_signatures<span class="op">(</span>Completions completions,</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>                                               ValueTransform value_transform <span class="op">=</span> <span class="op">{}</span>,</span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>                                               ErrorTransform error_transform <span class="op">=</span> <span class="op">{}</span>,</span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a>                                               StoppedCompletions stopped_completions <span class="op">=</span> <span class="op">{}</span>,</span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a>                                               OtherCompletions other_completions <span class="op">=</span> <span class="op">{})</span></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> <em>valid-completion-signatures</em> <span class="kw">auto</span>;</span></code></pre></div>
</blockquote>
<p>The above form of
<code class="sourceCode default">transform_completion_signatures</code>
is more natural to use from within a
<code class="sourceCode default">constexpr</code> function. It also
makes it simple to accept the default for some arguments as shown
below:</p>
<blockquote>
<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="co">// Transform just the error completion signatures:</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> cs2 <span class="op">=</span> transform_completion_signatures<span class="op">(</span>cs, <span class="op">{}</span>, <span class="op">[]&lt;</span><span class="kw">class</span> E<span class="op">&gt;()</span> <span class="op">{</span> <span class="cf">return</span> <span class="co">/* … */</span>; <span class="op">})</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>                                           <span class="co">//  ^^  Accept the default value transform</span></span></code></pre></div>
</blockquote>
<p>Since accepting the default transforms is simple, we are able to move
the infrequently used
<code class="sourceCode default">OtherCompletions</code> argument to the
end of the argument list.</p>
<p>Although the signature of this
<code class="sourceCode default">transform_completion_signatures</code>
function looks frightful, the implementation is quite straightforward,
and seeing it might make it less scary:</p>
<blockquote>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> As, <span class="kw">class</span> Fn<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> __apply_transform<span class="op">(</span><span class="kw">const</span> Fn<span class="op">&amp;</span> fn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(!</span><span class="kw">requires</span> <span class="op">{{</span>fn<span class="op">.</span><span class="kw">template</span> <span class="kw">operator</span><span class="op">()&lt;</span>As<span class="op">...&gt;()}</span> <span class="op">-&gt;</span> __valid_completion_signatures;<span class="op">})</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> invalid_completion_signature<span class="op">&lt;</span> … <span class="op">&gt;(</span> … <span class="op">)</span>; <span class="co">// see below</span></span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> fn<span class="op">.</span><span class="kw">template</span> <span class="kw">operator</span><span class="op">()&lt;</span>As<span class="op">...&gt;()</span>;</span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span> <span class="co">/* … as shown above … */</span> <span class="op">&gt;</span></span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> transform_completion_signatures<span class="op">(</span>Completions completions,</span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a>                                               ValueTransform value_transform,</span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a>                                               ErrorTransform error_transform,</span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a>                                               StoppedCompletions stopped_completions,</span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a>                                               OtherCompletions other_completions<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-15"><a href="#cb25-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> transform1 <span class="op">=</span> <span class="op">[=]&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;(</span>Tag<span class="op">(*)(</span>As<span class="op">...))</span> <span class="op">{</span></span>
<span id="cb25-16"><a href="#cb25-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Tag<span class="op">()</span> <span class="op">==</span> set_value<span class="op">)</span> <span class="co">// see &quot;<a href="#completion-tag-comparison">Completion tag comparison</a>&quot; below</span></span>
<span id="cb25-17"><a href="#cb25-17" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> __apply_transform<span class="op">&lt;</span>As<span class="op">...&gt;(</span>value_transform<span class="op">)</span>;</span>
<span id="cb25-18"><a href="#cb25-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Tag<span class="op">()</span> <span class="op">==</span> set_error<span class="op">)</span></span>
<span id="cb25-19"><a href="#cb25-19" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> __apply_transform<span class="op">&lt;</span>As<span class="op">...&gt;(</span>error_transform<span class="op">)</span>;</span>
<span id="cb25-20"><a href="#cb25-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span></span>
<span id="cb25-21"><a href="#cb25-21" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> stopped_completions;</span>
<span id="cb25-22"><a href="#cb25-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb25-23"><a href="#cb25-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-24"><a href="#cb25-24" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> transform_all <span class="op">=</span> <span class="op">[=](</span><span class="kw">auto</span><span class="op">*...</span> sigs<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-25"><a href="#cb25-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span>transform1<span class="op">(</span>sigs<span class="op">)</span> <span class="op">+...+</span> completion_signatures<span class="op">())</span>;</span>
<span id="cb25-26"><a href="#cb25-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb25-27"><a href="#cb25-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-28"><a href="#cb25-28" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">(</span>transform_all, completions<span class="op">)</span> <span class="op">+</span> other_completions;</span>
<span id="cb25-29"><a href="#cb25-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Like
<code class="sourceCode default">get_completion_signatures</code>,
<code class="sourceCode default">transform_completion_signatures</code>
always returns a specialization of
<code class="sourceCode default">completion_signatures</code> and
reports errors by throwing exceptions. It expects the lambdas passed to
it to do likewise (but handles it gracefully if they don’t).</p>
<h2 data-number="6.4" id="invalid_completion_signature"><span class="header-section-number">6.4</span>
<code class="sourceCode default">invalid_completion_signature</code><a href="#invalid_completion_signature" class="self-link"></a></h2>
<p>The reason for the design change is to permit the reporting of type
errors using exceptions. Let’s look at an example where it would be
desirable to throw an exception from
<code class="sourceCode default">get_completion_signatures</code>: the
<code class="sourceCode default">then</code> algorithm. We will use this
example to motivate the rest of the design changes.</p>
<p>The <code class="sourceCode default">then</code> algorithm attaches a
continuation to an async operation that executes when the operation
completes successfully. With this proposal, a
<code class="sourceCode default">then_sender</code>’s
<code class="sourceCode default">get_completion_signatures</code>
customization might be implemented as follows:</p>
<blockquote>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Fun<span class="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> then_sender<span class="op">&lt;</span>Sndr, Fun<span class="op">&gt;::</span>get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>  <span class="co">// compute the completions of the (properly cv-qualified) child:</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> Child <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>forward_like<span class="op">&lt;</span>Self<span class="op">&gt;(</span>declval<span class="op">&lt;</span>Sndr<span class="op">&amp;&gt;()))</span>;</span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> child_completions <span class="op">=</span> get_completion_signatures<span class="op">&lt;</span>Child, Env<span class="op">...&gt;()</span>;</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>   <span class="co">// This lambda is used to transform value completion signatures:</span></span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> value_transform <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;()</span> <span class="op">{</span></span>
<span id="cb26-10"><a href="#cb26-10" 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>invocable<span class="op">&lt;</span>Fun, As<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb26-11"><a href="#cb26-11" 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>Fun, As<span class="op">...&gt;</span>;</span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> completion_signatures<span class="op">&lt;</span>set_value_t<span class="op">(</span>Result<span class="op">)&gt;()</span>;</span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Oh no, the user made an error! Tell them about it.</span></span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a>      <span class="cf">throw</span> <em><code class="sourceCode default">some-exception-object</code></em>;</span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Transform just the value completions:</span></span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> transform_completion_signatures<span class="op">(</span>child_completions, value_transform<span class="op">)</span>;</span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>We would like to make it dead simple to throw an exception that will
convey a domain-specific diagnostic to the user. That way, the authors
of sender algorithms will be more likely to do so.</p>
<p>The
<code class="sourceCode default">invalid_completion_signature</code>
helper function is designed to make generating meaningful diagnostics
easy. As an example, here is how the
<code class="sourceCode default">then_sender</code>’s
<code class="sourceCode default">completion_signatures</code>
customization might use it:</p>
<blockquote>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;&gt;</span> <span class="kw">struct</span> IN_ALGORITHM;</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Fun<span class="op">&gt;</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> then_sender<span class="op">&lt;</span>Sndr, Fun<span class="op">&gt;::</span>get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* … */</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This lambda is used to transform value completion signatures:</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> value_transform <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;()</span> <span class="op">{</span></span>
<span id="cb27-9"><a href="#cb27-9" 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>invocable<span class="op">&lt;</span>Fun, As<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb27-10"><a href="#cb27-10" 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>Fun, As<span class="op">...&gt;</span>;</span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> completion_signatures<span class="op">&lt;</span>set_value_t<span class="op">(</span>Result<span class="op">)&gt;()</span>;</span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Oh no, the user made an error! Tell them about it.</span></span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> invalid_completion_signature<span class="op">&lt;</span></span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a>        IN_ALGORITHM<span class="op">&lt;</span>std<span class="op">::</span>execution<span class="op">::</span>then<span class="op">&gt;</span>,</span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a>        <span class="kw">struct</span> WITH_FUNCTION<span class="op">(</span>Fun<span class="op">)</span>,</span>
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a>        <span class="kw">struct</span> WITH_ARGUMENTS<span class="op">(</span>As<span class="op">...)</span></span>
<span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a>      <span class="op">&gt;(</span><span class="st">&quot;The function passed to std::execution::then is not callable &quot;</span></span>
<span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a>        <span class="st">&quot;with the values sent by the predecessor sender.&quot;</span><span class="op">)</span>;</span>
<span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* … */</span></span>
<span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>When the user of <code class="sourceCode default">then</code> makes a
mistake, say like with the expression
“<code class="sourceCode default">just(42) | then([]() {…})</code>”,
they will get a helpful diagnostic like the following (relevant bits
highlighted):</p>
<blockquote>
<div class="sourceCode">
<pre class="sourceCode"><code class="sourceCode">
<span><b>&lt;source&gt;:658:3: </b><b><span style="color:red">error: </span></b><b>call to immediate function &#39;operator|&lt;just_sender&lt;int&gt;&gt;&#39;
is not a constant expression</b></span>
  658 |   just(<span style="color:green">42</span>) | then([](){})
      | <b><span style="color:green">  ^</span></b>
<span><b><span style="color:green"></span></b><b>&lt;source&gt;:564:14: </b><b><span style="color:cyan">note: </span></b>&#39;operator|&lt;just_sender&lt;int&gt;&gt;&#39; is an immediate function be
cause its body contains a call to an immediate function &#39;__type_check_sender&lt;the
n_sender&lt;just_sender&lt;int&gt;, (lambda at &lt;source&gt;:658:19)&gt;&gt;&#39; and that call is not a
constant expression</span>
  564 |       <span style="color:blue">return</span> __type_check_sender(then_sender{{}, self.fn_, sndr});
      | <b><span style="color:green">             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span></b>
<span><b><span style="color:green"></span></b><b>&lt;source&gt;:358:11: </b><b><span style="color:cyan">note: </span></b>unhandled exception of type &#39;__sender_type_check_failure&lt;
const char *, <span style="background-color:yellow">IN_ALGORITHM&lt;then&gt;, WITH_FUNCTION ((lambda at &lt;source&gt;:658:19)), W
ITH_ARGUMENTS (int)&gt;&#39; with content {&amp;&quot;The function passed to std::execution::the
n is not callable with the values sent by the predecessor sender.&quot;[0]}</span> thrown fr
om here</span>
  358 |     <span style="color:blue">throw</span> __sender_type_check_failure&lt;Values...[<span style="color:green">0</span>], What...&gt;(values...);
      | <b><span style="color:green">          ^</span></b>
<b><span style="color:green"></span></b>1 error generated.
Compiler returned: 1</code></pre>
</div>
</blockquote>
<p>The above is the <em>complete</em> diagnostic, regardless of how
deeply nested the type error is. So long, megabytes of template
spew!</p>
<p>Lambdas passed to
<code class="sourceCode default">transform_completion_signatures</code>
<em>should</em> return a
<code class="sourceCode default">completion_signatures</code>
specialization (although
<code class="sourceCode default">transform_completion_signatures</code>
recovers gracefully when they do not). The return type of
<code class="sourceCode default">invalid_completion_signature</code> is
<code class="sourceCode default">completion_signature&lt;&gt;</code>. By
“returning” the result of calling
<code class="sourceCode default">invalid_completion_signature</code>,
the deduced return type of the lambda is a
<code class="sourceCode default">completion_signatures</code> type, as
it should be.</p>
<p>A possible implementation of the
<code class="sourceCode default">invalid_completion_signature</code>
function is shown below:</p>
<blockquote>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> What, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>sender-type-check-failure</em> <span class="op">:</span> std<span class="op">::</span>exception <span class="op">{</span> <span class="co">// exposition only</span></span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <em>sender-type-check-failure</em><span class="op">(</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="op">:</span> <em>args_</em><span class="op">{</span>std<span class="op">::</span>move<span class="op">(</span>args<span class="op">)...}</span> <span class="op">{}</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> what<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="kw">override</span> <span class="op">{</span> <span class="cf">return</span> <em>unspecified</em>; <span class="op">}</span>;</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>tuple<span class="op">&lt;</span>Args<span class="op">...&gt;</span> <em>args_</em>; <span class="co">// exposition only</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> What, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a><span class="op">[[</span><span class="at">noreturn</span>,<span class="at"> nodiscard</span><span class="op">]]</span></span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> completion_signatures<span class="op">&lt;&gt;</span> invalid_completion_signature<span class="op">(</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a>  <span class="cf">throw</span> <em>sender-type-check-failure</em><span class="op">&lt;</span>What<span class="op">...</span>, Args<span class="op">...&gt;{</span>std<span class="op">::</span>move<span class="op">(</span>args<span class="op">)...}</span>;</span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="6.5" id="get_child_completion_signatures"><span class="header-section-number">6.5</span>
<code class="sourceCode default">get_child_completion_signatures</code><a href="#get_child_completion_signatures" class="self-link"></a></h2>
<p>In the <code class="sourceCode default">then_sender</code> above,
computing a child sender’s completion signatures is a little
awkward:</p>
<blockquote>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// compute the completions of the (properly cv-qualified) child:</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> Child <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>forward_like<span class="op">&lt;</span>Self<span class="op">&gt;(</span>declval<span class="op">&lt;</span>Sndr<span class="op">&amp;&gt;()))</span>;</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> child_completions <span class="op">=</span> get_completion_signatures<span class="op">&lt;</span>Child, Env<span class="op">...&gt;()</span>;</span></code></pre></div>
</blockquote>
<p>Computing the completions of child senders will need to be done by
every sender adaptor algorithm. We can make this simpler with a
<code class="sourceCode default">get_child_completion_signatures</code>
helper function:</p>
<blockquote>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="co">// compute the completions of the (properly cv-qualified) child:</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> child_completions <span class="op">=</span> get_child_completion_signatures<span class="op">&lt;</span>Self, Sndr, Env<span class="op">...&gt;()</span>;</span></code></pre></div>
</blockquote>
<p>… where
<code class="sourceCode default">get_child_completion_signatures</code>
is defined as follows:</p>
<blockquote>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Parent, <span class="kw">class</span> Child, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> get_child_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>cvref-child-type</em> <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>forward_like<span class="op">&lt;</span>Parent<span class="op">&gt;(</span>declval<span class="op">&lt;</span>Child<span class="op">&amp;&gt;()))</span>;</span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> get_completion_signatures<span class="op">&lt;</span><em>cvref-child-type</em>, Env<span class="op">...&gt;()</span>;</span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="6.6" id="completion-tag-comparison"><span class="header-section-number">6.6</span> Completion tag comparison<a href="#completion-tag-comparison" class="self-link"></a></h2>
<p>For convenience, we can make the completion tag types
equality-comparable with each other. When writing sender adaptor
algorithms, code like the following will be common:</p>
<blockquote>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="op">[]&lt;</span><span class="kw">class</span> Tag, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;(</span>Tag<span class="op">(*)(</span>Args<span class="op">...))</span> <span class="op">{</span></span>
<span id="cb32-2"><a href="#cb32-2" 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>Tag, exec<span class="op">::</span>set_value_t<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Do something</span></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Do something else</span></span>
<span id="cb32-7"><a href="#cb32-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb32-8"><a href="#cb32-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Although certainly not hard, with reflection the tag type comparison
becomes a litte simpler:</p>
<blockquote>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(^^</span>Tag <span class="op">==</span> <span class="op">^^</span>exec<span class="op">::</span>set_value_t<span class="op">&gt;)</span> <span class="op">{</span></span></code></pre></div>
</blockquote>
<p>We can make this even easier by simply making the completion tag
types equality-comparable, as follows:</p>
<blockquote>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Tag<span class="op">()</span> <span class="op">==</span> exec<span class="op">::</span>set_value<span class="op">)</span> <span class="op">{</span></span></code></pre></div>
</blockquote>
<p>The author finds that this makes his code read better. Tag types
would compare equal to themselves and not-equal to the other two tag
types.</p>
<h2 data-number="6.7" id="eptr_completion_if"><span class="header-section-number">6.7</span>
<code class="sourceCode default">eptr_completion_if</code><a href="#eptr_completion_if" class="self-link"></a></h2>
<p>The following is a trivial utility that the author finds he uses
surprisingly often. Frequently an async operation can complete
exceptionally, but only under certain conditions. In cases such as
those, it is necessary to add a
<code class="sourceCode default">set_error_t(std::exception_ptr)</code>
signature to the set of completions, but only when the condition is
met.</p>
<p>This is made simpler with the following variable template:</p>
<blockquote>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span> PotentiallyThrowing<span class="op">&gt;</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eptr_completion_if <span class="op">=</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>conditional_t<span class="op">&lt;</span>PotentiallyThrowing,</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>                     completion_signatures<span class="op">&lt;</span>set_error_t<span class="op">(</span>exception_ptr<span class="op">)&gt;</span>,</span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a>                     completion_signatures<span class="op">&lt;&gt;&gt;()</span>;</span></code></pre></div>
</blockquote>
<p>Below is an example usage, from the
<code class="sourceCode default">then</code> sender:</p>
<blockquote>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Fun<span class="op">&gt;</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> then_sender<span class="op">&lt;</span>Sndr, Fun<span class="op">&gt;::</span>get_completion_signatures<span class="op">()</span> <span class="op">{</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> cs <span class="op">=</span> get_child_completion_signatures<span class="op">&lt;</span>Self, Sndr, Env<span class="op">...&gt;()</span>;</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> value_fn <span class="op">=</span> <span class="op">[]&lt;</span><span class="kw">class</span><span class="op">...</span> As<span class="op">&gt;()</span> <span class="op">{</span> <span class="co">/* … as shown in section &quot;<a href="#invalid_completion_signature">invalid_completion_signature</a>&quot; */</span> <span class="op">}</span>;</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> nothrow <span class="op">=</span> <span class="co">/* … false if Fun can throw for any set of the predecessor&#39;s values */</span>;</span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Use eptr_completion_if here as the &quot;extra&quot; set of completions that</span></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// will be added to the ones returned from the transforms.</span></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> transform_completion_signatures<span class="op">(</span>cs, value_fn, <span class="op">{}</span>, <span class="op">{}</span>, eptr_completion_if<span class="op">&lt;!</span>nothrow<span class="op">&gt;)</span>;</span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h1 data-number="7" id="questions-for-lewg"><span class="header-section-number">7</span> Questions for LEWG<a href="#questions-for-lewg" class="self-link"></a></h1>
<p>Assuming we want to change how completion signatures are computed as
proposed in this paper, the author would appreciate LEWG’s feedback
about the suggested additions.</p>
<ol type="1">
<li><p>Do we want to use
<code class="sourceCode default">operator+</code> to join two
<code class="sourceCode default">completion_signature</code>
objects?</p></li>
<li><p>Do we want to make <code class="sourceCode default">completion_signatures&lt;Sigs...&gt;</code>
<em><code class="sourceCode default">tuple-like</code></em> (where <code class="sourceCode default">completion_signatures&lt;Sigs...&gt;()</code>
behaves like
<code class="sourceCode default">tuple&lt;Sigs*...&gt;()</code>)?</p></li>
<li><p>Should we drop the
<code class="sourceCode default">transform_completion_signatures</code>
alias template?</p></li>
<li><p>Should we add a
<code class="sourceCode default">make_completion_signatures</code>
helper function that returns an instance of a
<code class="sourceCode default">completion_signatures</code> type with
its function types normalized and made unique?</p></li>
<li><p>Should we replace the
<code class="sourceCode default">transform_completion_signatures</code>
alias template with a <code class="sourceCode default">consteval</code>
function that does the same thing but for values?</p></li>
<li><p>Do we want the
<code class="sourceCode default">invalid_completion_signature</code>
helper function to make it easy to generate good diagnostics when
type-checking a sender fails.</p></li>
<li><p>Do we want the
<code class="sourceCode default">get_child_completion_signatures</code>
helper function to make is easy for sender adaptors to get a (properly
<em>cv</em>-qualified) child sender’s completion signatures?</p></li>
<li><p>Do we want to make the completion tag types
(<code class="sourceCode default">set_value_t</code>, etc.)
<code class="sourceCode default">constexpr</code> equality-comparable
with each other?</p></li>
<li><p>Do we want the
<code class="sourceCode default">eptr_completion_if</code> variable
template, which is an object of type <code class="sourceCode default">completion_signatures&lt;set_error_t(std::exception_ptr)&gt;</code>
or <code class="sourceCode default">completion_signatures&lt;&gt;</code>
depending on a <code class="sourceCode default">bool</code> template
parameter?</p></li>
</ol>
<h1 data-number="8" id="implementation-experience"><span class="header-section-number">8</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>The design proposed in this paper has been prototyped and can be
found on <a href="https://godbolt.org/z/Y1vPcn6Kr">Compiler
Explorer</a><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>.</p>
<h1 data-number="9" id="proposed-wording"><span class="header-section-number">9</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: This
wording is relative to the current working draft with the addition of
<span class="citation" data-cites="P3164R3">[<a href="#ref-P3164R3" role="doc-biblioref">P3164R3</a>]</span> ]</span></p>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.general] as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="add" style="color: #006e28"><ins>For function type
<span><code class="sourceCode default">R(Args...)</code></span>, let
<span><code class="sourceCode default"><em><code class="sourceCode default">NORMALIZE-SIG</code></em>(R(Args...))</code></span>
denote the type <span><code class="sourceCode default">R(<em><code class="sourceCode default">remove-rvalue-reference-t</code></em>&lt;Args&gt;...)</code></span>
where
<em><span><code class="sourceCode default">remove-rvalue-reference-t</code></span></em>
is an alias template that removes an rvalue reference from a
type.</ins></span></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
For function types <code class="sourceCode default">F1</code> and
<code class="sourceCode default">F2</code> <span class="rm" style="color: #bf0303"><del>denoting
<span><code class="sourceCode default">R1(Args1...)</code></span> and
<span><code class="sourceCode default">R2(Args2...)</code></span>,
respectively,</del></span>
<code class="sourceCode default"><em><code class="sourceCode default">MATCHING-SIG</code></em>(F1, F2)</code>
is <code class="sourceCode default">true</code> if and only if
<code>same_as&lt;<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">R1(Args1&amp;&amp;...), R2(Args2&amp;&amp;...)</code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em>NORMALIZE-SIG</em>(F1), <em>NORMALIZE-SIG</em>(F2)</code></span></ins></span>&gt;</code>
is <code class="sourceCode default">true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
For a subexpression <code class="sourceCode default">err</code>, let
<code class="sourceCode default">Err</code> be
<code class="sourceCode default">decltype((err))</code> and let
<code class="sourceCode default"><em><code class="sourceCode default">AS-EXCEPT-PTR</code></em>(err)</code>
be <span class="ednote" style="color: #0000ff">[ Editor&#39;s note: … as
before ]</span></p>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[execution.syn] as follows: ]</span></p>
<blockquote>
<p><b>Header <code class="sourceCode default">&lt;execution&gt;</code>
synopsis [execution.syn]</b></p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;font-style:italic">… as before …</span></span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> sender_in <span class="op">=</span> <em>see below</em>;</span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr&gt;</code></span></ins></span></span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">concept dependent_sender = <em>see below</em>;</code></span></ins></span></span>
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-10"><a href="#cb37-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Rcvr<span class="op">&gt;</span></span>
<span id="cb37-11"><a href="#cb37-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> sender_to <span class="op">=</span> <em>see below</em>;</span>
<span id="cb37-12"><a href="#cb37-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-13"><a href="#cb37-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb37-14"><a href="#cb37-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> <em><code class="sourceCode default">type-list</code></em>;                                           <span class="co">// exposition only</span></span>
<span id="cb37-15"><a href="#cb37-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-16"><a href="#cb37-16" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">// [exec.getcomplsigs], completion signatures</code></span></del></span></span>
<span id="cb37-17"><a href="#cb37-17" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">struct get_completion_signatures_t;</code></span></del></span></span>
<span id="cb37-18"><a href="#cb37-18" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">inline constexpr get_completion_signatures_t get_completion_signatures {};</code></span></del></span></span>
<span id="cb37-19"><a href="#cb37-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-20"><a href="#cb37-20" aria-hidden="true" tabindex="-1"></a>  <span class="ednote" style="color: #0000ff">[ Editor&#39;s note: <code class="sourceCode default">This alias is moved below and modified.</code>
]</span></span>
<span id="cb37-21"><a href="#cb37-21" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></del></span></span>
<span id="cb37-22"><a href="#cb37-22" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">requires sender_in&lt;Sndr, Env...&gt;</code></span></del></span></span>
<span id="cb37-23"><a href="#cb37-23" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">using completion_signatures_of_t = <em><code class="sourceCode default">call-result-t</code></em>&lt;get_completion_signatures_t, Sndr, Env...&gt;;</code></span></del></span></span>
<span id="cb37-24"><a href="#cb37-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-25"><a href="#cb37-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;</span></span>
<span id="cb37-26"><a href="#cb37-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em><code class="sourceCode default">decayed-tuple</code></em> <span class="op">=</span> tuple<span class="op">&lt;</span>decay_t<span class="op">&lt;</span>Ts<span class="op">&gt;...&gt;</span>;                <span class="co">// exposition only</span></span>
<span id="cb37-27"><a href="#cb37-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-28"><a href="#cb37-28" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;font-style:italic">… as before …</span></span>
<span id="cb37-29"><a href="#cb37-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-30"><a href="#cb37-30" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [exec.util], sender and receiver utilities</span></span>
<span id="cb37-31"><a href="#cb37-31" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [exec.util.cmplsig] <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">completion signatures</code></span></ins></span></span></span>
<span id="cb37-32"><a href="#cb37-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Fn<span class="op">&gt;</span></span>
<span id="cb37-33"><a href="#cb37-33" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em><code class="sourceCode default">completion-signature</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;                   <span class="co">// exposition only</span></span>
<span id="cb37-34"><a href="#cb37-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-35"><a href="#cb37-35" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em><code class="sourceCode default">completion-signature</code></em><span class="op">...</span> Fns<span class="op">&gt;</span></span>
<span id="cb37-36"><a href="#cb37-36" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> completion_signatures <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">{}</code></span></del></span>;</span>
<span id="cb37-37"><a href="#cb37-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-38"><a href="#cb37-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sigs<span class="op">&gt;</span></span>
<span id="cb37-39"><a href="#cb37-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em><code class="sourceCode default">valid-completion-signatures</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;            <span class="co">// exposition only</span></span>
<span id="cb37-40"><a href="#cb37-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-41"><a href="#cb37-41" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">struct <em><code class="sourceCode default">dependent-sender-error</code></em> {};</code></span></ins></span>                             <span class="add" style="color: #006e28"><ins><em><span><code class="sourceCode default">// exposition only</code></span></em></ins></span></span>
<span id="cb37-42"><a href="#cb37-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-43"><a href="#cb37-43" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">// [exec.getcomplsigs]</code></span></ins></span></span>
<span id="cb37-44"><a href="#cb37-44" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb37-45"><a href="#cb37-45" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">consteval auto get_completion_signatures() -&gt; <em><code class="sourceCode default">valid-completion-signatures</code></em> auto;</code></span></ins></span></span>
<span id="cb37-46"><a href="#cb37-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-47"><a href="#cb37-47" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb37-48"><a href="#cb37-48" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">requires sender_in&lt;Sndr, Env...&gt;</code></span></ins></span></span>
<span id="cb37-49"><a href="#cb37-49" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">using completion_signatures_of_t = decltype(get_completion_signatures&lt;Sndr, Env...&gt;());</code></span></ins></span></span>
<span id="cb37-50"><a href="#cb37-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-51"><a href="#cb37-51" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">// [exec.util.cmplsig.trans]</code></span></del></span></span>
<span id="cb37-52"><a href="#cb37-52" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;</code></span></del></span></span>
<span id="cb37-53"><a href="#cb37-53" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> InputSignatures,</code></span></del></span></span>
<span id="cb37-54"><a href="#cb37-54" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> AdditionalSignatures = completion_signatures&lt;&gt;,</code></span></del></span></span>
<span id="cb37-55"><a href="#cb37-55" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class...&gt; class SetValue = <em><code class="sourceCode default">see below</code></em>,</code></span></del></span></span>
<span id="cb37-56"><a href="#cb37-56" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class&gt; class SetError = <em><code class="sourceCode default">see below</code></em>,</code></span></del></span></span>
<span id="cb37-57"><a href="#cb37-57" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> SetStopped = completion_signatures&lt;set_stopped_t()&gt;&gt;</code></span></del></span></span>
<span id="cb37-58"><a href="#cb37-58" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">using transform_completion_signatures = completion_signatures&lt;<em><code class="sourceCode default">see below</code></em>&gt;;</code></span></del></span></span>
<span id="cb37-59"><a href="#cb37-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-60"><a href="#cb37-60" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;</code></span></del></span></span>
<span id="cb37-61"><a href="#cb37-61" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">sender Sndr,</code></span></del></span></span>
<span id="cb37-62"><a href="#cb37-62" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">class Env = env&lt;&gt;,</code></span></del></span></span>
<span id="cb37-63"><a href="#cb37-63" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> AdditionalSignatures = completion_signatures&lt;&gt;,</code></span></del></span></span>
<span id="cb37-64"><a href="#cb37-64" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class...&gt; class SetValue = <em><code class="sourceCode default">see below</code></em>,</code></span></del></span></span>
<span id="cb37-65"><a href="#cb37-65" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class&gt; class SetError = <em><code class="sourceCode default">see below</code></em>,</code></span></del></span></span>
<span id="cb37-66"><a href="#cb37-66" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> SetStopped = completion_signatures&lt;set_stopped_t()&gt;&gt;</code></span></del></span></span>
<span id="cb37-67"><a href="#cb37-67" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">requires sender_in&lt;Sndr, Env&gt;</code></span></del></span></span>
<span id="cb37-68"><a href="#cb37-68" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">using transform_completion_signatures_of =</code></span></del></span></span>
<span id="cb37-69"><a href="#cb37-69" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">transform_completion_signatures&lt;</code></span></del></span></span>
<span id="cb37-70"><a href="#cb37-70" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">completion_signatures_of_t&lt;Sndr, Env&gt;,</code></span></del></span></span>
<span id="cb37-71"><a href="#cb37-71" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">AdditionalSignatures, SetValue, SetError, SetStopped&gt;;</code></span></del></span></span>
<span id="cb37-72"><a href="#cb37-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-73"><a href="#cb37-73" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [exec.run.loop], run_loop</span></span>
<span id="cb37-74"><a href="#cb37-74" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> run_loop;</span>
<span id="cb37-75"><a href="#cb37-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-76"><a href="#cb37-76" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;font-style:italic">… as before …</span></span>
<span id="cb37-77"><a href="#cb37-77" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-78"><a href="#cb37-78" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Add the
following paragraph after [execution.syn] para 3 (this is moved from
[exec.snd.concepts]) ]</span></p>
<div class="add" style="color: #006e28">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="add" style="color: #006e28"><ins>A type models the
exposition-only concept
<em><span><code class="sourceCode default">valid-completion-signatures</code></span></em>
if it denotes a specialization of the
<span><code class="sourceCode default">completion_signatures</code></span>
class template.</ins></span></p>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Modify
[exec.snd.general] as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Subclauses [exec.factories] and [exec.adapt] define customizable
algorithms that return senders. Each algorithm has a default
implementation. Let <code class="sourceCode default">sndr</code> be the
result of an invocation of such an algorithm or an object equal to the
result ([concepts.equality]), and let
<code class="sourceCode default">Sndr</code> be
<code class="sourceCode default">decltype((sndr))</code>. Let
<code class="sourceCode default">rcvr</code> be a receiver of type
<code class="sourceCode default">Rcvr</code> with associated environment
<code class="sourceCode default">env</code> of type
<code class="sourceCode default">Env</code> such that
<code class="sourceCode default">sender_to&lt;Sndr, Rcvr&gt;</code> is
<code class="sourceCode default">true</code>. For the default
implementation of the algorithm that produced
<code class="sourceCode default">sndr</code>, connecting
<code class="sourceCode default">sndr</code> to
<code class="sourceCode default">rcvr</code> and starting the resulting
operation state ([exec.async.ops]) necessarily results in the potential
evaluation ([basic.def.odr]) of a set of completion operations whose
first argument is a subexpression equal to
<code class="sourceCode default">rcvr</code>. Let
<code class="sourceCode default">Sigs</code> be a pack of completion
signatures corresponding to this set of completion operations, and let
<code class="sourceCode default">CS</code> be the type of the expression
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">get_completion_signatures(sndr, env)</code></span></del></span>
<span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">get_completion_signatures&lt;Sndr, Env&gt;()</code></span></ins></span>.
Then <code class="sourceCode default">CS</code> is a specialization of
the class template
<code class="sourceCode default">completion_signatures</code>
([exec.util.cmplsig]), the set of whose template arguments is
<code class="sourceCode default">Sigs</code>. If none of the types in
<code class="sourceCode default">Sigs</code> are dependent on the type
<code class="sourceCode default">Env</code>, then the expression <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">get_completion_signatures(sndr)</code></span></del></span>
<span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">get_completion_signatures&lt;Sndr&gt;()</code></span></ins></span>
is well-formed and its type is
<code class="sourceCode default">CS</code>. If a user-provided
implementation of the algorithm that produced
<code class="sourceCode default">sndr</code> is selected instead of the
default:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> Any
completion signature that is in the set of types denoted by <code class="sourceCode default">completion_signatures_of_t&lt;Sndr, Env&gt;</code>
and that is not part of <code class="sourceCode default">Sigs</code>
shall correspond to error or stopped completion operations, unless
otherwise specified.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> If
none of the types in <code class="sourceCode default">Sigs</code> are
dependent on the type <code class="sourceCode default">Env</code>, then
<code class="sourceCode default">completion_signatures_of_t&lt;Sndr&gt;</code>
and <code class="sourceCode default">completion_signatures_of_t&lt;Sndr, Env&gt;</code>
shall denote the same type.</p></li>
</ul>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: In
[exec.snd.expos], insert the following paragraph after para 22 and
before para 23 (moving the exposition-only alias template out of para 24
and into its own para so it can be used from elsewhere): ]</span></p>
<div class="add" style="color: #006e28">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">23</a></span> Let
<em><code class="sourceCode default">valid-specialization</code></em> be
the following alias template:</p>
<blockquote>
<div class="sourceCode" id="cb38"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a>template&lt;template&lt;class...&gt; class T, class... Args&gt;</span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>  concept <em><code class="sourceCode default">valid-specialization</code></em> = requires { typename T&lt;Args...&gt;; }; // exposition only</span></code></pre></div>
</blockquote>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: In
[exec.snd.expos] para 23 add the mandate below, and in para 24, change
the definition of the exposition-only
<em><code class="sourceCode default">basic-sender</code></em> as
follows: ]</span></p>
<blockquote>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Tag, <span class="kw">class</span> Data <span class="op">=</span> see below, <span class="kw">class</span><span class="op">...</span> Child<span class="op">&gt;</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">make-sender</code></em><span class="op">(</span>Tag tag, Data<span class="op">&amp;&amp;</span> data, Child<span class="op">&amp;&amp;...</span> child<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">23</a></span>
<em>Mandates</em>: The following expressions are
<code class="sourceCode default">true</code>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.1)</a></span>
<code class="sourceCode default">semiregular&lt;Tag&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.2)</a></span>
<code class="sourceCode default"><em><code class="sourceCode default">movable-value</code></em>&lt;Data&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.3)</a></span>
<code class="sourceCode default">(sender&lt;Child&gt; &amp;&amp;...)</code></p></li>
</ul>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.4)</a></span>
<span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">dependent_sender&lt;Sndr&gt; || sender_in&lt;Sndr&gt;</code></span>,
where <span><code class="sourceCode default">Sndr</code></span> is
<span><code class="sourceCode default"><em><code class="sourceCode default">basic-sender</code></em>&lt;Tag, Data, Child...&gt;</code></span>
as defined below.</ins></span></p>
<p><em>Recommended practice:</em> When this mandate fails because <code class="sourceCode default">get_completion_signatures&lt;Sndr&gt;()</code>
would exit with an exception, implementations are encouraged to include
information about the exception in the resulting diagnostic.</p></li>
</ul>
</blockquote>

</div>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">24</a></span>
<em>Returns</em>: A prvalue of type <code class="sourceCode default"><em><code class="sourceCode default">basic-sender</code></em>&lt;Tag, decay_t&lt;Data&gt;, decay_t&lt;Child&gt;...&gt;</code>
that has been direct-list-initialized with the forwarded arguments,
where <em><code class="sourceCode default">basic-sender</code></em> is
the following exposition-only class template except as noted below.</p>
<blockquote>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Tag<span class="op">&gt;</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em><code class="sourceCode default">completion-tag</code></em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a>    same_as<span class="op">&lt;</span>Tag, set_value_t<span class="op">&gt;</span> <span class="op">||</span> same_as<span class="op">&lt;</span>Tag, set_error_t<span class="op">&gt;</span> <span class="op">||</span> same_as<span class="op">&lt;</span>Tag, set_stopped_t<span class="op">&gt;</span>;</span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;template&lt;class...&gt; class T, class... Args&gt;</code></span></del></span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">concept <em><code class="sourceCode default">valid-specialization</code></em> = requires { typename T&lt;Args...&gt;; }; // exposition only</code></span></del></span></span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span>  <span class="co">// exposition only</span></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-attrs</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-env</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-state</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">start</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">complete</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;font-style:italic">… as before …</span></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template &lt;class Sndr&gt;</code></span></ins></span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">using <em><code class="sourceCode default">data-type</code></em> = decltype(declval&lt;Sndr&gt;().template <em><code class="sourceCode default">get</code></em>&lt;1&gt;());     // exposition only</code></span></ins></span></span>
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="dt">size_t</span> I <span class="op">=</span> <span class="dv">0</span><span class="op">&gt;</span></span>
<span id="cb40-26"><a href="#cb40-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em><code class="sourceCode default">child-type</code></em> <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>declval<span class="op">&lt;</span>Sndr<span class="op">&gt;().</span><span class="kw">template</span> <em><code class="sourceCode default">get</code></em><span class="op">&lt;</span>I<span class="op">+</span><span class="dv">2</span><span class="op">&gt;())</span>;     <span class="co">// exposition only</span></span>
<span id="cb40-27"><a href="#cb40-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-28"><a href="#cb40-28" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;font-style:italic">… as before …</span></span>
<span id="cb40-29"><a href="#cb40-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-30"><a href="#cb40-30" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></del></span></span>
<span id="cb40-31"><a href="#cb40-31" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">using <em><code class="sourceCode default">completion-signatures-for</code></em> = <em><code class="sourceCode default">see below</code></em>; // exposition only</code></span></del></span></span>
<span id="cb40-32"><a href="#cb40-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-33"><a href="#cb40-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Tag, <span class="kw">class</span> Data, <span class="kw">class</span><span class="op">...</span> Child<span class="op">&gt;</span></span>
<span id="cb40-34"><a href="#cb40-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">basic-sender</code></em> <span class="op">:</span> <em><code class="sourceCode default">product-type</code></em><span class="op">&lt;</span>Tag, Data, Child<span class="op">...&gt;</span> <span class="op">{</span>  <span class="co">// exposition only</span></span>
<span id="cb40-35"><a href="#cb40-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> sender_concept <span class="op">=</span> sender_t;</span>
<span id="cb40-36"><a href="#cb40-36" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> <em><code class="sourceCode default">indices-for</code></em> <span class="op">=</span> index_sequence_for<span class="op">&lt;</span>Child<span class="op">...&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb40-37"><a href="#cb40-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-38"><a href="#cb40-38" aria-hidden="true" tabindex="-1"></a>    <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> get_env<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb40-39"><a href="#cb40-39" aria-hidden="true" tabindex="-1"></a>      <span class="kw">auto</span><span class="op">&amp;</span> <span class="op">[</span>_, data, <span class="op">...</span>child<span class="op">]</span> <span class="op">=</span> <span class="op">*</span><span class="kw">this</span>;</span>
<span id="cb40-40"><a href="#cb40-40" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span>Tag<span class="op">&gt;::</span><em><code class="sourceCode default">get-attrs</code></em><span class="op">(</span>data, child<span class="op">...)</span>;</span>
<span id="cb40-41"><a href="#cb40-41" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb40-42"><a href="#cb40-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-43"><a href="#cb40-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><em><code class="sourceCode default">decays-to</code></em><span class="op">&lt;</span><em><code class="sourceCode default">basic-sender</code></em><span class="op">&gt;</span> Self, receiver Rcvr<span class="op">&gt;</span></span>
<span id="cb40-44"><a href="#cb40-44" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="fu">connect</span><span class="op">(</span><span class="kw">this</span> Self<span class="op">&amp;&amp;</span> self, Rcvr rcvr<span class="op">)</span> <span class="kw">noexcept</span><span class="op">(</span><em><code class="sourceCode default">see below</code></em><span class="op">)</span></span>
<span id="cb40-45"><a href="#cb40-45" aria-hidden="true" tabindex="-1"></a>      <span class="op">-&gt;</span> <em><code class="sourceCode default">basic-operation</code></em><span class="op">&lt;</span>Self, Rcvr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb40-46"><a href="#cb40-46" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="op">{</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Self<span class="op">&gt;(</span>self<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>rcvr<span class="op">)}</span>;</span>
<span id="cb40-47"><a href="#cb40-47" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb40-48"><a href="#cb40-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-49"><a href="#cb40-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><em><code class="sourceCode default">decays-to</code></em><span class="op">&lt;</span><em><code class="sourceCode default">basic-sender</code></em><span class="op">&gt;</span> Self, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb40-50"><a href="#cb40-50" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static consteval</code></span></ins></span> <span class="kw">auto</span> get_completion_signatures<span class="op">(</span><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">this Self&amp;&amp; self, Env&amp;&amp;... env</code></span></del></span><span class="op">)</span> <span class="rm" style="color: #bf0303"><del>noexcept</del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">;</code></span></ins></span></span>
<span id="cb40-51"><a href="#cb40-51" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">-&gt; <em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Self, Env...&gt; {</code></span></del></span></span>
<span id="cb40-52"><a href="#cb40-52" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">return {};</code></span></del></span></span>
<span id="cb40-53"><a href="#cb40-53" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">}</code></span></del></span></span>
<span id="cb40-54"><a href="#cb40-54" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb40-55"><a href="#cb40-55" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: In
[exec.snd.expos], replace para 39 with the paragraphs shown below and
renumber subsequent paragraphs: ]</span></p>
<blockquote>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized">39</a></span> Let
<code class="sourceCode default">Sndr</code> be a (possibly
<code class="sourceCode default">const</code>-qualified) specialization
<em><code class="sourceCode default">basic-sender</code></em> or an
lvalue reference of such, let
<code class="sourceCode default">Rcvr</code> be the type of a receiver
with an associated environment of type
<code class="sourceCode default">Env</code>. If the type <code class="sourceCode default"><em><code class="sourceCode default">basic-operation</code></em>&lt;Sndr, Rcvr&gt;</code>
is well-formed, let <code class="sourceCode default">op</code> be an
lvalue subexpression of that type. Then <code class="sourceCode default"><em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Sndr, Env&gt;</code>
denotes a specialization of
<code class="sourceCode default">completion_signatures</code>, the set
of whose template arguments corresponds to the set of completion
operations that are potentially evaluated ([basic.def.odr]) as a result
of evaluating <code class="sourceCode default">op.start()</code>.
Otherwise, <code class="sourceCode default"><em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Sndr, Env&gt;</code>
is ill-formed. If <code class="sourceCode default"><em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Sndr, Env&gt;</code>
is well-formed and its type is not dependent upon the type
<code class="sourceCode default">Env</code>, <code class="sourceCode default"><em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Sndr&gt;</code>
is well-formed and denotes the same type; otherwise, <code class="sourceCode default"><em><code class="sourceCode default">completion-signatures-for</code></em>&lt;Sndr&gt;</code>
is ill-formed.</p>
</div>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb41"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a>template &lt;class Sndr, class... Env&gt;</span>
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a>  static constexpr void <em><code class="sourceCode default">default-impls</code></em>::<em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
Let <code class="sourceCode default">FwdEnv</code> be a pack of the
types <code class="sourceCode default">decltype(<em><code class="sourceCode default">FWD-ENV</code></em>(declval&lt;Env&gt;()))...</code>,
and let <code class="sourceCode default">Is</code> be the pack of
integral template arguments of the
<code class="sourceCode default">integer_sequence</code> specialization
denoted by
<code class="sourceCode default"><em><code class="sourceCode default">indices-for</code></em>&lt;Sndr&gt;</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Effects</em>: Equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb42"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a>(get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr, Is&gt;, FwdEnv...&gt;(), ...)</span></code></pre></div>
</blockquote>
<div class="sourceCode" id="cb43"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Tag, class Data, class... Child&gt;</span>
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a>  template &lt;class Sndr, class... Env&gt;</span>
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a>    static consteval auto <em><code class="sourceCode default">basic-sender</code></em>&lt;Tag, Data, Child...&gt;::get_completion_signatures();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
Let <code class="sourceCode default">Rcvr</code> be the type of a
receiver whose environment has type
<code class="sourceCode default">E</code>, where
<code class="sourceCode default">E</code> is the first type in the list
<code class="sourceCode default">Env..., <em>unspecified</em></code>.
Let <code class="sourceCode default">CS</code> be a type determined as
follows:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span> If
the following expression is well-formed and a core constant
expression:</p>
<blockquote>
<div class="sourceCode" id="cb44"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><em><code class="sourceCode default">impls-for</code></em>&lt;Tag&gt;::template <em><code class="sourceCode default">check-types</code></em>&lt;Sndr, Env...&gt;()</span></code></pre></div>
</blockquote>
<p>let <code class="sourceCode default">op</code> be an lvalue
subexpression whose type is <code class="sourceCode default">connect_result_t&lt;Sndr, Rcvr&gt;</code>.
Then <code class="sourceCode default">CS</code> is the specialization of
<code class="sourceCode default">completion_signatures</code> the set of
whose template arguments correspond to the set of completion operations
that are potentially evaluated ([basic.def.odr]) as a result of
evaluating <code class="sourceCode default">op.start()</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.2)</a></span>
Otherwise, <code class="sourceCode default">CS</code> is
<code class="sourceCode default">completion_signatures&lt;&gt;</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Effects</em>: Equivalent to</p>
<blockquote>
<div class="sourceCode" id="cb45"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><em><code class="sourceCode default">impls-for</code></em>&lt;Tag&gt;::template <em><code class="sourceCode default">check-types</code></em>&lt;Sndr, Env...&gt;();</span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>return CS();</span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Throws</em>: An exception of an unspecified type if the expression
<code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;Tag&gt;::template <em><code class="sourceCode default">check-types</code></em>&lt;Sndr, Env...&gt;()</code>
is ill-formed.</p>
</div>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
the specification of
<em><code class="sourceCode default">write-env</code></em> in
[exec.snd.expos] para 40-43 as follows: ]</span></p>
<blockquote>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>sender Sndr, queryable Env<span class="op">&gt;</span></span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">write-env</code></em><span class="op">(</span>Sndr<span class="op">&amp;&amp;</span> sndr, Env<span class="op">&amp;&amp;</span> env<span class="op">)</span>;         <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">40</a></span>
<em><code class="sourceCode default">write-env</code></em> is an
exposition-only sender adaptor that, when connected with a receiver
<code class="sourceCode default">rcvr</code>, connects the adapted
sender with a receiver whose execution environment is the result of
joining the queryable argument
<code class="sourceCode default">env</code> to the result of
<code class="sourceCode default">get_env(rcvr)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">41</a></span> Let
<em><code class="sourceCode default">write-env-t</code></em> be an
exposition-only empty class type.</p>
<p><span class="marginalizedparent"><a class="marginalized">42</a></span>
<em>Returns</em>:</p>
<blockquote>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><em><code class="sourceCode default">make-sender</code></em><span class="op">(</span><em><code class="sourceCode default">write-env-t</code></em><span class="op">()</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Env<span class="op">&gt;(</span>env<span class="op">)</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Sndr<span class="op">&gt;(</span>sndr<span class="op">))</span></span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">43</a></span>
<em>Remarks</em>: The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<em><code class="sourceCode default">write-env-t</code></em> as
follows:</p>
<blockquote>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb48-2"><a href="#cb48-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span><em><code class="sourceCode default">write-env-t</code></em><span class="op">&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr auto <em><code class="sourceCode default">join-env</code></em>(const auto&amp; state, const auto&amp; env) noexcept {</code></span></ins></span></span>
<span id="cb48-4"><a href="#cb48-4" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">return <em><code class="sourceCode default">see below</code></em>;</code></span></ins></span></span>
<span id="cb48-5"><a href="#cb48-5" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">}</code></span></ins></span></span>
<span id="cb48-6"><a href="#cb48-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-7"><a href="#cb48-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-env</code></em> <span class="op">=</span></span>
<span id="cb48-8"><a href="#cb48-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">[](</span><span class="kw">auto</span>, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> state, <span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> rcvr<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb48-9"><a href="#cb48-9" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">see below</code></em></code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em><code class="sourceCode default">join-env</code></em>(state, get_env(rcvr))</code></span></ins></span>;</span>
<span id="cb48-10"><a href="#cb48-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb48-11"><a href="#cb48-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb48-12"><a href="#cb48-12" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb48-13"><a href="#cb48-13" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb48-14"><a href="#cb48-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(43.1)</a></span>
Invocation of <code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;<em><code class="sourceCode default">write-env-t</code></em>&gt;​::<em><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">​get-env</code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">join-env</code></span></ins></span></em></code>
returns an object <code class="sourceCode default">e</code> such that
<code class="sourceCode default">decltype(e)</code> models
<code class="sourceCode default">queryable</code> and given a query
object <code class="sourceCode default">q</code>, the expression
<code class="sourceCode default">e.query(q)</code> is
expression-equivalent to
<code class="sourceCode default">state.query(q)</code> if that
expression is valid, otherwise,
<code class="sourceCode default">e.query(q)</code> is
expression-equivalent to <code class="sourceCode default"><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">get_env(rcvr)</code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">env</code></span></ins></span>.query(q)</code>.</li>
</ul>
<div class="add" style="color: #006e28">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(43.2)</a></span>
<span class="add" style="color: #006e28"><ins>For type
<span><code class="sourceCode default">Sndr</code></span> and pack
<span><code class="sourceCode default">Env</code></span>, let
<span><code class="sourceCode default">State</code></span> be
<span><code class="sourceCode default"><em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;</code></span>
and let <span><code class="sourceCode default">JoinEnv</code></span> be
the pack <span><code class="sourceCode default">decltype(<em><code class="sourceCode default">join-env</code></em>(declval&lt;State&gt;(), declval&lt;Env&gt;()))</code></span>.
Then <span><code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;<em><code class="sourceCode default">write-env-t</code></em>&gt;​::<em><code class="sourceCode default">check-types</code></em>&lt;Sndr, Env...&gt;()</code></span>
is expression-equivalent to <span><code class="sourceCode default">get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr&gt;, JoinEnv...&gt;()</code></span>.</ins></span></li>
</ul>

</div>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Add the
following new paragraphs to the end of [exec.snd.expos] ]</span></p>
<blockquote>
<div class="add" style="color: #006e28">

<span class="marginalizedparent"><a class="marginalized">?</a></span>
<div>
<div class="sourceCode" id="cb49"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a>template&lt;class... Fns&gt;</span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>struct <em><code class="sourceCode default">overload-set</code></em> : Fns... {</span>
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a>  using Fns::operator()...;</span>
<span id="cb49-4"><a href="#cb49-4" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
</div>
<span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Moved from
[exec.on] para 6 and modified. ]</span>
<div>
<div class="sourceCode" id="cb50"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a>struct <em><code class="sourceCode default">not-a-sender</code></em> {</span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>  using sender_concept = sender_t;</span>
<span id="cb50-3"><a href="#cb50-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb50-4"><a href="#cb50-4" aria-hidden="true" tabindex="-1"></a>  template&lt;class Sndr&gt;</span>
<span id="cb50-5"><a href="#cb50-5" aria-hidden="true" tabindex="-1"></a>  static constexpr auto get_completion_signatures() -&gt; completion_signatures&lt;&gt; {</span>
<span id="cb50-6"><a href="#cb50-6" aria-hidden="true" tabindex="-1"></a>    throw <em>unspecified</em>;</span>
<span id="cb50-7"><a href="#cb50-7" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb50-8"><a href="#cb50-8" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
</div>

</div>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.snd.concepts] para 1 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code class="sourceCode default">sender</code> concept <span style="color:blue;font-style:italic">… as before …</span> to produce an
operation state.</p>
<blockquote>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class Sigs&gt;</code></span></del></span></span>
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a>    <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">concept <em><code class="sourceCode default">valid-completion-signatures</code></em> = <em><code class="sourceCode default">see below</code></em>;            // exposition only</code></span></del></span></span>
<span id="cb51-4"><a href="#cb51-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-5"><a href="#cb51-5" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;auto&gt;</code></span></ins></span></span>
<span id="cb51-6"><a href="#cb51-6" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">concept <em><code class="sourceCode default">is-constant</code></em> = true;</code></span></ins></span>                                 <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">// exposition only</code></span></ins></span></span>
<span id="cb51-7"><a href="#cb51-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-8"><a href="#cb51-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb51-9"><a href="#cb51-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em><code class="sourceCode default">is-sender</code></em> <span class="op">=</span>                                         <span class="co">// exposition only</span></span>
<span id="cb51-10"><a href="#cb51-10" aria-hidden="true" tabindex="-1"></a>      derived_from<span class="op">&lt;</span><span class="kw">typename</span> Sndr<span class="op">::</span>sender_concept, sender_t<span class="op">&gt;</span>;</span>
<span id="cb51-11"><a href="#cb51-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-12"><a href="#cb51-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb51-13"><a href="#cb51-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em><code class="sourceCode default">enable-sender</code></em> <span class="op">=</span>                                     <span class="co">// exposition only</span></span>
<span id="cb51-14"><a href="#cb51-14" aria-hidden="true" tabindex="-1"></a>      <em><code class="sourceCode default">is-sender</code></em><span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">||</span></span>
<span id="cb51-15"><a href="#cb51-15" aria-hidden="true" tabindex="-1"></a>      <em><code class="sourceCode default">is-awaitable</code></em><span class="op">&lt;</span>Sndr, <em><code class="sourceCode default">env-promise</code></em><span class="op">&lt;</span>env<span class="op">&lt;&gt;&gt;&gt;</span>;                   <span class="co">// [exec.awaitable]</span></span>
<span id="cb51-16"><a href="#cb51-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-17"><a href="#cb51-17" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr&gt;</code></span></ins></span></span>
<span id="cb51-18"><a href="#cb51-18" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">consteval bool <em><code class="sourceCode default">is-dependent-sender-helper</code></em>() try {</code></span></ins></span>           <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">// exposition only</code></span></ins></span></span>
<span id="cb51-19"><a href="#cb51-19" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">get_completion_signatures&lt;Sndr&gt;();</code></span></ins></span></span>
<span id="cb51-20"><a href="#cb51-20" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">return false;</code></span></ins></span></span>
<span id="cb51-21"><a href="#cb51-21" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">} catch (<em><code class="sourceCode default">dependent-sender-error</code></em>&amp;) {</code></span></ins></span></span>
<span id="cb51-22"><a href="#cb51-22" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">return true;</code></span></ins></span></span>
<span id="cb51-23"><a href="#cb51-23" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">}</code></span></ins></span></span>
<span id="cb51-24"><a href="#cb51-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-25"><a href="#cb51-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr<span class="op">&gt;</span></span>
<span id="cb51-26"><a href="#cb51-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> sender <span class="op">=</span></span>
<span id="cb51-27"><a href="#cb51-27" aria-hidden="true" tabindex="-1"></a>      <span class="dt">bool</span><span class="op">(</span><em><code class="sourceCode default">enable-sender</code></em><span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>Sndr<span class="op">&gt;&gt;)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-28"><a href="#cb51-28" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <span class="op">(</span><span class="kw">const</span> remove_cvref_t<span class="op">&lt;</span>Sndr<span class="op">&gt;&amp;</span> sndr<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-29"><a href="#cb51-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span> get_env<span class="op">(</span>sndr<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> <em><code class="sourceCode default">queryable</code></em>;</span>
<span id="cb51-30"><a href="#cb51-30" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-31"><a href="#cb51-31" aria-hidden="true" tabindex="-1"></a>      move_constructible<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>Sndr<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-32"><a href="#cb51-32" aria-hidden="true" tabindex="-1"></a>      constructible_from<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>Sndr<span class="op">&gt;</span>, Sndr<span class="op">&gt;</span>;</span>
<span id="cb51-33"><a href="#cb51-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-34"><a href="#cb51-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span><span class="op">...</span> Env<span class="op">&gt;</span></span>
<span id="cb51-35"><a href="#cb51-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> sender_in <span class="op">=</span></span>
<span id="cb51-36"><a href="#cb51-36" aria-hidden="true" tabindex="-1"></a>      sender<span class="op">&lt;</span>Sndr<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-37"><a href="#cb51-37" aria-hidden="true" tabindex="-1"></a>      <span class="op">(</span>queryable<span class="op">&lt;</span>Env<span class="op">&gt;</span> <span class="op">&amp;&amp;...)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-38"><a href="#cb51-38" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em><code class="sourceCode default">is-constant</code></em>&lt;get_completion_signatures&lt;Sndr, Env...&gt;()&gt;</code></span></ins></span></span>
<span id="cb51-39"><a href="#cb51-39" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">requires (Sndr&amp;&amp; sndr, Env&amp;&amp;... env) {</code></span></del></span></span>
<span id="cb51-40"><a href="#cb51-40" aria-hidden="true" tabindex="-1"></a>        <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">{ get_completion_signatures(std::forward&lt;Sndr&gt;(sndr), std::forward&lt;Env&gt;(env)...) }</code></span></del></span></span>
<span id="cb51-41"><a href="#cb51-41" aria-hidden="true" tabindex="-1"></a>          <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">-&gt; <em><code class="sourceCode default">valid-completion-signatures</code></em>;</code></span></del></span></span>
<span id="cb51-42"><a href="#cb51-42" aria-hidden="true" tabindex="-1"></a>      <span class="rm" style="color: #bf0303"><del>}</del></span>;</span>
<span id="cb51-43"><a href="#cb51-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-44"><a href="#cb51-44" aria-hidden="true" tabindex="-1"></a>  <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr&gt;</code></span></ins></span></span>
<span id="cb51-45"><a href="#cb51-45" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">concept dependent_sender =</code></span></ins></span></span>
<span id="cb51-46"><a href="#cb51-46" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">sender&lt;Sndr&gt; &amp;&amp; bool_constant&lt;<em><code class="sourceCode default">is-dependent-sender-helper</code></em>&lt;Sndr&gt;()&gt;::value;</code></span></ins></span></span>
<span id="cb51-47"><a href="#cb51-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb51-48"><a href="#cb51-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Rcvr<span class="op">&gt;</span></span>
<span id="cb51-49"><a href="#cb51-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> sender_to <span class="op">=</span></span>
<span id="cb51-50"><a href="#cb51-50" aria-hidden="true" tabindex="-1"></a>      sender_in<span class="op">&lt;</span>Sndr, env_of_t<span class="op">&lt;</span>Rcvr<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-51"><a href="#cb51-51" aria-hidden="true" tabindex="-1"></a>      receiver_of<span class="op">&lt;</span>Rcvr, completion_signatures_of_t<span class="op">&lt;</span>Sndr, env_of_t<span class="op">&lt;</span>Rcvr<span class="op">&gt;&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb51-52"><a href="#cb51-52" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <span class="op">(</span>Sndr<span class="op">&amp;&amp;</span> sndr, Rcvr<span class="op">&amp;&amp;</span> rcvr<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-53"><a href="#cb51-53" aria-hidden="true" tabindex="-1"></a>        <span class="fu">connect</span><span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Sndr<span class="op">&gt;(</span>sndr<span class="op">)</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Rcvr<span class="op">&gt;(</span>rcvr<span class="op">))</span>;</span>
<span id="cb51-54"><a href="#cb51-54" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span>;</span>
<span id="cb51-55"><a href="#cb51-55" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Strike
[exec.snd.concepts] para 3 (this para is moved to [execution.syn]):
]</span></p>
<div class="rm" style="color: #bf0303">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<span class="rm" style="color: #bf0303"><del>A type models the
exposition-only concept
<em><span><code class="sourceCode default">valid-completion-signatures</code></span></em>
if it denotes a specialization of the
<span><code class="sourceCode default">completion_signatures</code></span>
class template.</del></span></p>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.getcomplsigs] as follows: ]</span></p>
<blockquote>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code class="sourceCode default">get_completion_signatures</code> is a
customization point object. Let sndr be an expression such that
<code class="sourceCode default">decltype((sndr))</code> is
<code class="sourceCode default">Sndr</code>, and let
<code class="sourceCode default">env</code> be a pack of zero or one
expression. If
<code class="sourceCode default">sizeof...(env) == 0</code> is
<code class="sourceCode default">true</code>, let
<code class="sourceCode default">new_sndr</code> be
<code class="sourceCode default">sndr</code>; otherwise, let
<code class="sourceCode default">new_sndr</code> be the expression <code class="sourceCode default">transform_sender(decltype(<em><code class="sourceCode default">get-domain-late</code></em>(sndr, env...)){}, sndr, env...)</code>.
Let <code class="sourceCode default">NewSndr</code> be
<code class="sourceCode default">decltype((new_sndr))</code>. Then <code class="sourceCode default">get_completion_signatures(sndr, env...)</code>
is expression-equivalent to
<code class="sourceCode default">(void(sndr), void(env)..., CS())</code>
except that <code class="sourceCode default">void(sndr)</code> and
<code class="sourceCode default">void(env)...</code> are indeterminately
sequenced, where <code class="sourceCode default">CS</code> is:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code class="sourceCode default">decltype(new_sndr.get_completion_signatures(env...))</code>
if that type is well-formed,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
Otherwise, if
<code class="sourceCode default">sizeof...(env) == 1</code> is
<code class="sourceCode default">true</code>, then <code class="sourceCode default">decltype(new_sndr.get_completion_signatures())</code>
if that expression is well-formed,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
Otherwise, <code class="sourceCode default">remove_cvref_t&lt;NewSndr&gt;::completion_signatures</code>
if that type is well-formed,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
Otherwise, if <code class="sourceCode default"><em><code class="sourceCode default">is-awaitable</code></em>&lt;NewSndr, <em><code class="sourceCode default">env-promise</code></em>&lt;decltype((env))&gt;...&gt;</code>
is <code class="sourceCode default">true</code>, then:</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a>completion_signatures&lt;</span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a>  <em><code class="sourceCode default">SET-VALUE-SIG</code></em>(await-result-type&lt;NewSndr, env-promise&lt;Env&gt;&gt;),        //  ([exec.snd.concepts])</span>
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a>  set_error_t(exception_ptr),</span>
<span id="cb52-4"><a href="#cb52-4" aria-hidden="true" tabindex="-1"></a>  set_stopped_t()&gt;</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
Otherwise, <code class="sourceCode default">CS</code> is
ill-formed.</p></li>
</ul>

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

<div class="sourceCode" id="cb53"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a>template &lt;class Sndr, class... Env&gt;</span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>  consteval auto get_completion_signatures() -&gt; <code class="sourceCode default"><em><code class="sourceCode default">valid-completion-signatures</code></em> auto</code>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
Let <code class="sourceCode default">NewSndr</code> be
<code class="sourceCode default">Sndr</code> if
<code class="sourceCode default">sizeof...(Env) == 1</code> is
<code class="sourceCode default">false</code>; otherwise,
<code class="sourceCode default">decltype(new_sndr)</code> where
<code class="sourceCode default">new_sndr</code> is the following
expression:</p>
<blockquote>
<div class="sourceCode" id="cb54"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a>transform_sender(</span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a>  decltype(<em><code class="sourceCode default">get-domain-late</code></em>(declval&lt;Sndr&gt;(), declval&lt;Env&gt;()...)){},</span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a>  declval&lt;Sndr&gt;(),</span>
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a>  declval&lt;Env&gt;()...)</span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Requires</em>:
<code class="sourceCode default">sizeof...(Env) &lt;= 1</code> is
<code class="sourceCode default">true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Effects</em>: Given the following exposition-only entities:</p>
<blockquote>
<div class="sourceCode" id="cb55"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a>  using <em><code class="sourceCode default">completion-signatures-result-t</code></em> =                  // exposition only</span>
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a>    decltype(remove_reference_t&lt;Sndr&gt;::template get_completion_signatures&lt;Sndr, Env...&gt;());</span>
<span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb55-6"><a href="#cb55-6" aria-hidden="true" tabindex="-1"></a>  concept <em><code class="sourceCode default">dependent-sender-without-env</code></em> =                  // exposition only</span>
<span id="cb55-7"><a href="#cb55-7" aria-hidden="true" tabindex="-1"></a>    (sizeof...(Env) == 0) &amp;&amp; !requires { typename <em><code class="sourceCode default">completion-signatures-result-t</code></em>&lt;Sndr&gt;; };</span>
<span id="cb55-8"><a href="#cb55-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb55-9"><a href="#cb55-9" aria-hidden="true" tabindex="-1"></a>template&lt;completion_signatures&gt;</span>
<span id="cb55-10"><a href="#cb55-10" aria-hidden="true" tabindex="-1"></a>  concept <em><code class="sourceCode default">has-constexpr-completions-helper</code></em> = true;        // exposition only</span>
<span id="cb55-11"><a href="#cb55-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb55-12"><a href="#cb55-12" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb55-13"><a href="#cb55-13" aria-hidden="true" tabindex="-1"></a>  concept <em><code class="sourceCode default">has-constexpr-completions</code></em> =                     // exposition only</span>
<span id="cb55-14"><a href="#cb55-14" aria-hidden="true" tabindex="-1"></a>    <em><code class="sourceCode default">has-constexpr-completions-helper</code></em>&lt;</span>
<span id="cb55-15"><a href="#cb55-15" aria-hidden="true" tabindex="-1"></a>      remove_reference_t&lt;Sndr&gt;::template get_completion_signatures&lt;Sndr, Env...&gt;()&gt;;</span></code></pre></div>
</blockquote>
<p>Equivalent to:
<code class="sourceCode default">return <em>e</em>;</code> where
<em><code class="sourceCode default">e</code></em> is
expression-equivalent to the following:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<code class="sourceCode default">remove_reference_t&lt;Sndr&gt;::template get_completion_signatures&lt;Sndr, Env...&gt;()</code>
if <code class="sourceCode default"><em><code class="sourceCode default">has-constexpr-completions</code></em>&lt;Sndr, Env...&gt;</code>
is <code class="sourceCode default">true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.2)</a></span>
<code class="sourceCode default">remove_reference_t&lt;Sndr&gt;::template get_completion_signatures&lt;Sndr&gt;()</code>
if <code class="sourceCode default">sizeof...(Env) == 1 &amp;&amp; <em><code class="sourceCode default">has-constexpr-completions</code></em>&lt;Sndr&gt;</code>
is <code class="sourceCode default">true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.3)</a></span>
Otherwise, <code class="sourceCode default">remove_cvref_t&lt;NewSndr&gt;::completion_signatures</code>
if that type is well-formed,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.4)</a></span>
Otherwise, <code class="sourceCode default">(throw <em><code class="sourceCode default">dependent-sender-error</code></em>(), completion_signatures())</code>
if <code class="sourceCode default"><em><code class="sourceCode default">dependent-sender-without-env</code></em>&lt;Sndr, Env...&gt;</code>
is <code class="sourceCode default">true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.5)</a></span>
Otherwise, <code class="sourceCode default">(throw <em><code class="sourceCode default">unspecified</code></em>, completion_signatures())</code>
if <code class="sourceCode default">requires { typename <em><code class="sourceCode default">completion-signatures-result-t</code></em>&lt;Sndr, Env...&gt;; }</code>
is <code class="sourceCode default">false</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.6)</a></span>
Otherwise:</p>
<blockquote>
<div class="sourceCode" id="cb56"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a>(remove_reference_t&lt;Sndr&gt;::template get_completion_signatures&lt;Sndr, Env&gt;(),</span>
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a>throw <em><code class="sourceCode default">unspecified</code></em>,</span>
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a>completion_signatures())</span></code></pre></div>
</blockquote></li>
</ul>

</div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
If <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">get_completion_signatures(sndr)</code></span>
is well-formed and its type denotes a specialization of the
<span><code class="sourceCode default">completion_signatures</code></span>
class template</del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em><code class="sourceCode default">has-constexpr-completions</code></em>&lt;Sndr&gt;</code></span>
is
<span><code class="sourceCode default">true</code></span></ins></span>,
then <code class="sourceCode default">Sndr</code> is a non-dependent
sender type ([async.ops]).</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Given a type <code class="sourceCode default">Env</code>, if <code class="sourceCode default">completion_signatures_of_t&lt;Sndr&gt;</code>
and <code class="sourceCode default">completion_signatures_of_t&lt;Sndr, Env&gt;</code>
are both well-formed, they shall denote the same type.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let <code class="sourceCode default">rcvr</code> be an rvalue whose type
<code class="sourceCode default">Rcvr</code> models
<code class="sourceCode default">receiver</code>, and let
<code class="sourceCode default">Sndr</code> be the type of a sender
such that <code class="sourceCode default">sender_in&lt;Sndr, env_of_t&lt;Rcvr&gt;&gt;</code>
is <code class="sourceCode default">true</code>. Let
<code class="sourceCode default">Sigs...</code> be the template
arguments of the
<code class="sourceCode default">completion_signatures</code>
specialization named by <code class="sourceCode default">completion_signatures_of_t&lt;Sndr, env_of_t&lt;Rcvr&gt;&gt;</code>.
Let <code class="sourceCode default">CSO</code> be a completion
function. If sender <code class="sourceCode default">Sndr</code> or its
operation state cause the expression
<code class="sourceCode default">CSO(rcvr, args...)</code> to be
potentially evaluated ([basic.def.odr]) then there shall be a signature
<code class="sourceCode default">Sig</code> in
<code class="sourceCode default">Sigs...</code> such that</p>
<blockquote>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><em><code class="sourceCode default">MATCHING-SIG</code></em><span class="op">(</span><em><code class="sourceCode default">decayed-typeof</code></em><span class="op">&lt;</span>CSO<span class="op">&gt;(</span><span class="kw">decltype</span><span class="op">(</span>args<span class="op">)...)</span>, Sig<span class="op">)</span></span></code></pre></div>
</blockquote>
<p>is <code class="sourceCode default">true</code> ([exec.general]).</p>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: At the
very bottom of [exec.connect], change the <em>Mandates</em> of para 6 as
follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The expression
<code class="sourceCode default">connect(sndr, rcvr)</code> is
expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<code class="sourceCode default">new_sndr.connect(rcvr)</code> if that
expression is well-formed.</p>
<p><em>Mandates</em>: The type of the expression above satisfies
<code class="sourceCode default">operation_state</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
Otherwise, <code class="sourceCode default"><em><code class="sourceCode default">connect-awaitable</code></em>(new_sndr, rcvr)</code>.</p></li>
</ul>
<p><em>Mandates</em>: <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">sender&lt;Sndr&gt; &amp;&amp; receiver&lt;Rcvr&gt;</code></span>
is
<span><code class="sourceCode default">true</code></span>.</del></span><span class="add" style="color: #006e28"><ins>The following are all
<span><code class="sourceCode default">true</code></span>:</ins></span></p>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.3)</a></span>
<code class="sourceCode default">sender&lt;Sndr&gt;</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.4)</a></span>
<code class="sourceCode default">receiver&lt;Rcvr&gt;</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.5)</a></span>
<code class="sourceCode default"><em><code class="sourceCode default">has-constexpr-completions</code></em>&lt;Sndr, env_of_t&lt;Rcvr&gt;&gt;</code>.</p></li>
</ul>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: In
[exec.read.env] para 3, make the following change: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">read_env</code> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb58-3"><a href="#cb58-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span><em><code class="sourceCode default">decayed-typeof</code></em><span class="op">&lt;</span>read_env<span class="op">&gt;&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb58-4"><a href="#cb58-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">start</code></em> <span class="op">=</span></span>
<span id="cb58-5"><a href="#cb58-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">[](</span><span class="kw">auto</span> query, <span class="kw">auto</span><span class="op">&amp;</span> rcvr<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb58-6"><a href="#cb58-6" aria-hidden="true" tabindex="-1"></a>        <em><code class="sourceCode default">TRY-SET-VALUE</code></em><span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>rcvr<span class="op">)</span>, query<span class="op">(</span>get_env<span class="op">(</span>rcvr<span class="op">)))</span>;</span>
<span id="cb58-7"><a href="#cb58-7" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span>;</span>
<span id="cb58-8"><a href="#cb58-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb58-9"><a href="#cb58-9" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class Env&gt;</code></span></ins></span></span>
<span id="cb58-10"><a href="#cb58-10" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb58-11"><a href="#cb58-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb58-12"><a href="#cb58-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb59"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class Env&gt;</span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> Let
<code class="sourceCode default">Q</code> be <code class="sourceCode default">decay_t&lt;<em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;&gt;</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<em>Throws</em>: An exception of an unspecified type if the expression
<code class="sourceCode default">Q()(env)</code> is ill-formed or has
type <code class="sourceCode default">void</code>, where
<code class="sourceCode default">env</code> is an lvalue subexpression
whose type is <code class="sourceCode default">Env</code>.</p></li>
</ul>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.shedule.from] para 4 and insert a new para between 6 and 7 as
follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">schedule_from_t</code> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span>schedule_from_t<span class="op">&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-attrs</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below;</code></em></span>
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-state</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below;</code></em></span>
<span id="cb60-6"><a href="#cb60-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">complete</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below;</code></em></span>
<span id="cb60-7"><a href="#cb60-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb60-8"><a href="#cb60-8" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb60-9"><a href="#cb60-9" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb60-10"><a href="#cb60-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb60-11"><a href="#cb60-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The member <span style="color:blue;font-style=italic">… as before
…</span></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The member <span style="color:blue;font-style=italic">… as before
…</span></p>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb61"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<em>Effects</em>: Equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb62"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a>get_completion_signatures&lt;schedule_result_t&lt;<em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;&gt;&gt;,</span>
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a>                          decltype(<em><code class="sourceCode default">FWD-ENV</code></em>(declval&lt;Env&gt;()))...&gt;();</span>
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a><em><code class="sourceCode default">default-impls</code></em>::<em><code class="sourceCode default">check-types</code></em>&lt;Sndr, Env...&gt;();</span></code></pre></div>
</blockquote>

</div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
Objects of the local class
<em><code class="sourceCode default">state-type</code></em> <span style="color:blue;font-style=italic">… as before …</span></p>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.on] para 6 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Otherwise: Let
<em><code class="sourceCode default">not-a-scheduler</code></em> be an
unspecified empty class type<span class="add" style="color: #006e28"><ins>.</ins></span><span class="rm" style="color: #bf0303"><del>, and let
<em><span><code class="sourceCode default">not-a-sender</code></span></em>
be the exposition-only type:</del></span></p>
<div class="rm" style="color: #bf0303">

<blockquote>
<div class="sourceCode" id="cb63"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a>struct <em><code class="sourceCode default">not-a-sender</code></em> {</span>
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a>  using sender_concept = sender_t;</span>
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a>  auto get_completion_signatures(auto&amp;&amp;) const {</span>
<span id="cb63-5"><a href="#cb63-5" aria-hidden="true" tabindex="-1"></a>    return <em>see below</em>;</span>
<span id="cb63-6"><a href="#cb63-6" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb63-7"><a href="#cb63-7" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
</blockquote>

</div>
<p><span class="rm" style="color: #bf0303"><del>where the member
function
<span><code class="sourceCode default">get_completion_signatures</code></span>
returns an object of a type that is not a specialization of the
<span><code class="sourceCode default">completion_signatures</code></span>
class template.</del></span></p>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Delete
[exec.on] para 9 as follows: ]</span></p>
<div class="rm" style="color: #bf0303">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<span class="rm" style="color: #bf0303"><del><em>Recommended
practice</em>: Implementations should use the return type of <span><code class="sourceCode default"><em><code class="sourceCode default">not-a-sender​</code></em>::​get_completion_signatures</code></span>
to inform users that their usage of on is incorrect because there is no
available scheduler onto which to restore execution.</del></span></p>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Revert
the change to [exec.then] made by P3164R3, and then change [exec.then]
para 4 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<em><code class="sourceCode default">then-cpo</code></em> as
follows:</p>
<blockquote>
<div class="sourceCode" id="cb64"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span><em><code class="sourceCode default">decayed-typeof</code></em><span class="op">&lt;</span><em><code class="sourceCode default">then-cpo</code></em><span class="op">&gt;&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> complete <span class="op">=</span></span>
<span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">[]&lt;</span><span class="kw">class</span> Tag, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">(</span><span class="kw">auto</span>, <span class="kw">auto</span><span class="op">&amp;</span> fn, <span class="kw">auto</span><span class="op">&amp;</span> rcvr, Tag, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb64-7"><a href="#cb64-7" aria-hidden="true" tabindex="-1"></a>          <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>same_as<span class="op">&lt;</span>Tag, <em><code class="sourceCode default">decayed-typeof</code></em><span class="op">&lt;</span><em><code class="sourceCode default">set-cpo</code></em><span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb64-8"><a href="#cb64-8" aria-hidden="true" tabindex="-1"></a>            <em><code class="sourceCode default">TRY-SET-VALUE</code></em><span class="op">(</span>rcvr,</span>
<span id="cb64-9"><a href="#cb64-9" aria-hidden="true" tabindex="-1"></a>                          invoke<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>fn<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="cb64-10"><a href="#cb64-10" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb64-11"><a href="#cb64-11" aria-hidden="true" tabindex="-1"></a>            Tag<span class="op">()(</span>std<span class="op">::</span>move<span class="op">(</span>rcvr<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="cb64-12"><a href="#cb64-12" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb64-13"><a href="#cb64-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb64-14"><a href="#cb64-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-15"><a href="#cb64-15" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb64-16"><a href="#cb64-16" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb64-17"><a href="#cb64-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb64-18"><a href="#cb64-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<span class="marginalizedparent"><a class="marginalized">?</a></span>
<div>
<div class="sourceCode" id="cb65"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
</div>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<em>Effects:</em> Equivalent to:</p>
<div class="sourceCode" id="cb66"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb66-1"><a href="#cb66-1" aria-hidden="true" tabindex="-1"></a>auto cs = get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr, 0&gt;, Env...&gt;();</span>
<span id="cb66-2"><a href="#cb66-2" aria-hidden="true" tabindex="-1"></a>auto fn = []&lt;class... Ts&gt;(set_value_t(*)(Ts...)) {</span>
<span id="cb66-3"><a href="#cb66-3" aria-hidden="true" tabindex="-1"></a>  if constexpr (!invocable&lt;remove_cvref_t&lt;<em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;&gt;, Ts...&gt;)</span>
<span id="cb66-4"><a href="#cb66-4" aria-hidden="true" tabindex="-1"></a>    throw <em><code class="sourceCode default">unspecified</code></em>;</span>
<span id="cb66-5"><a href="#cb66-5" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb66-6"><a href="#cb66-6" aria-hidden="true" tabindex="-1"></a>cs.<em><code class="sourceCode default">for-each</code></em>(<em><code class="sourceCode default">overload-set</code></em>{fn, [](auto){}});</span></code></pre></div></li>
</ul>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Revert
the change to [exec.let] made by P3164R3, and then change [exec.let]
para 5 and insert a new para after 5 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<em><code class="sourceCode default">let-cpo</code></em> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb67"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> State, <span class="kw">class</span> Rcvr, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> <em><code class="sourceCode default">let-bind</code></em><span class="op">(</span>State<span class="op">&amp;</span> state, Rcvr<span class="op">&amp;</span> rcvr, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;      <span class="co">// exposition only</span></span>
<span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb67-6"><a href="#cb67-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span><em><code class="sourceCode default">decayed-typeof</code></em><span class="op">&lt;</span><em><code class="sourceCode default">let-cpo</code></em><span class="op">&gt;&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb67-7"><a href="#cb67-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-state</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb67-8"><a href="#cb67-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">complete</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb67-9"><a href="#cb67-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb67-10"><a href="#cb67-10" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb67-11"><a href="#cb67-11" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb67-12"><a href="#cb67-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb67-13"><a href="#cb67-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<span class="marginalizedparent"><a class="marginalized">?</a></span>
<div>
<div class="sourceCode" id="cb68"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
</div>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<em>Effects:</em> Equivalent to:</p>
<div class="sourceCode" id="cb69"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb69-1"><a href="#cb69-1" aria-hidden="true" tabindex="-1"></a>using LetFn = remove_cvref_t&lt;<em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;&gt;;</span>
<span id="cb69-2"><a href="#cb69-2" aria-hidden="true" tabindex="-1"></a>auto cs = get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr&gt;, Env...&gt;();</span>
<span id="cb69-3"><a href="#cb69-3" aria-hidden="true" tabindex="-1"></a>auto fn = []&lt;class... Ts&gt;(<em><code class="sourceCode default">decayed-typeof</code></em>&lt;<em><code class="sourceCode default">set-cpo</code></em>&gt;(*)(Ts...)) {</span>
<span id="cb69-4"><a href="#cb69-4" aria-hidden="true" tabindex="-1"></a>  if constexpr (!invocable&lt;LetFn, Ts...&gt;)</span>
<span id="cb69-5"><a href="#cb69-5" aria-hidden="true" tabindex="-1"></a>    throw <em><code class="sourceCode default">unspecified</code></em>;</span>
<span id="cb69-6"><a href="#cb69-6" aria-hidden="true" tabindex="-1"></a>  else if constexpr (!sender&lt;invoke_result_t&lt;LetFn, Ts...&gt;&gt;)</span>
<span id="cb69-7"><a href="#cb69-7" aria-hidden="true" tabindex="-1"></a>    throw <em><code class="sourceCode default">unspecified</code></em>;</span>
<span id="cb69-8"><a href="#cb69-8" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb69-9"><a href="#cb69-9" aria-hidden="true" tabindex="-1"></a>cs.<em><code class="sourceCode default">for-each</code></em>(<em><code class="sourceCode default">overload-set</code></em>(fn, [](auto){}));</span></code></pre></div></li>
</ul>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Revert
the change to [exec.bulk] made by P3164R3, and then change [exec.bulk]
para 3 and insert a new para after 5 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">bulk_t</code> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb70"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span>bulk_t<span class="op">&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">complete</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb70-5"><a href="#cb70-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb70-6"><a href="#cb70-6" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb70-7"><a href="#cb70-7" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb70-8"><a href="#cb70-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb70-9"><a href="#cb70-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The member <code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;bulk_t&gt;::<em><code class="sourceCode default">complete</code></em></code>
is <span style="color:blue;font-style=italic">… as before …</span></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<span style="color:blue;font-style=italic">… as before …</span></p>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<span class="marginalizedparent"><a class="marginalized">?</a></span>
<div>
<div class="sourceCode" id="cb71"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb71-2"><a href="#cb71-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
</div>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<em>Effects:</em> Equivalent to:</p>
<div class="sourceCode" id="cb72"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a>auto cs = get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr&gt;, Env...&gt;();</span>
<span id="cb72-2"><a href="#cb72-2" aria-hidden="true" tabindex="-1"></a>auto fn = []&lt;class... Ts&gt;(set_value_t(*)(Ts...)) {</span>
<span id="cb72-3"><a href="#cb72-3" aria-hidden="true" tabindex="-1"></a>  if constexpr (!invocable&lt;remove_cvref_t&lt;<em><code class="sourceCode default">data-type</code></em>&lt;Sndr&gt;&gt;, Ts...&gt;)</span>
<span id="cb72-4"><a href="#cb72-4" aria-hidden="true" tabindex="-1"></a>    throw <em><code class="sourceCode default">unspecified</code></em>;</span>
<span id="cb72-5"><a href="#cb72-5" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb72-6"><a href="#cb72-6" aria-hidden="true" tabindex="-1"></a>cs.<em><code class="sourceCode default">for-each</code></em>(<em><code class="sourceCode default">overload-set</code></em>{fn, [](auto){}});</span></code></pre></div></li>
</ul>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Revert
the change to [exec.split] made by P3164R3, and then change [exec.split]
para 3 and insert a new para after 3 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The name <code class="sourceCode default">split</code> denotes a
pipeable sender adaptor object. <span class="rm" style="color: #bf0303"><del>For a subexpression
<span><code class="sourceCode default">sndr</code></span>, let
<span><code class="sourceCode default">Sndr</code></span> be
<span><code class="sourceCode default">decltype((sndr))</code></span>.
If <span><code class="sourceCode default">sender_in&lt;Sndr, <em><code class="sourceCode default">split-env</code></em>&gt;</code></span>
is <span><code class="sourceCode default">false</code></span>,
<span><code class="sourceCode default">split(sndr)</code></span> is
ill-formed.</del></span></p>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">split_t</code> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb73"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a>namespace std::execution {</span>
<span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a>  template&lt;&gt;</span>
<span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a>  struct <em><code class="sourceCode default">impls-for</code></em>&lt;split_t&gt; : <em><code class="sourceCode default">default-impls</code></em> {</span>
<span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a>    template&lt;class Sndr&gt;</span>
<span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a>    static constexpr void <em><code class="sourceCode default">check-types</code></em>() {</span>
<span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a>      <em><code class="sourceCode default">default-impls</code></em>::<em><code class="sourceCode default">check-types</code></em>&lt;Sndr, <em><code class="sourceCode default">split-env</code></em>&gt;();</span>
<span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a>    }</span>
<span id="cb73-8"><a href="#cb73-8" aria-hidden="true" tabindex="-1"></a>  };</span>
<span id="cb73-9"><a href="#cb73-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
</blockquote>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.when.all] paras 2-4 and insert two new paras after 4 as follows:
]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The names <code class="sourceCode default">when_all</code> and
<code class="sourceCode default">when_all_with_variant</code> denote
customization point objects. Let
<code class="sourceCode default">sndrs</code> be a pack of
subexpressions, let <code class="sourceCode default">Sndrs</code> be a
pack of the types
<code class="sourceCode default">decltype((sndrs))...</code>, and let
<code class="sourceCode default">CD</code> be the type <code class="sourceCode default">common_type_t&lt;decltype(<em><code class="sourceCode default">get-domain-early</code></em>(sndrs))...&gt;</code>
<span class="add" style="color: #006e28"><ins>, and let
<span><code class="sourceCode default">CD2</code></span> be
<span><code class="sourceCode default">CD</code></span> if
<span><code class="sourceCode default">CD</code></span> is well-formed,
and <span><code class="sourceCode default">default_domain</code></span>
otherwise.</ins></span>. The expressions
<code class="sourceCode default">when_all(sndrs...)</code> and
<code class="sourceCode default">when_all_with_variant(sndrs...)</code>
are ill-formed if any of the following is true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code class="sourceCode default">sizeof...(sndrs)</code> is
<code class="sourceCode default">0</code>, or</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code class="sourceCode default">(sender&lt;Sndrs&gt; &amp;&amp; ...)</code>
is <code class="sourceCode default">false</code><span class="rm" style="color: #bf0303"><del>, or</del></span><span class="add" style="color: #006e28"><ins>.</ins></span></p></li>
</ul>
<div class="rm" style="color: #bf0303">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">CD</code></span>
is ill-formed.</del></span></li>
</ul>

</div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The expression
<code class="sourceCode default">when_all(sndrs...)</code> is
expression-equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb74"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb74-1"><a href="#cb74-1" aria-hidden="true" tabindex="-1"></a>transform_sender<span class="op">(</span><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">CD()</code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">CD2()</code></span></ins></span>, <em><code class="sourceCode default">make-sender</code></em><span class="op">(</span>when_all, <span class="op">{}</span>, sndrs<span class="op">...))</span></span></code></pre></div>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
The exposition-only class template
<em><code class="sourceCode default">impls-for</code></em>
([exec.snd.general]) is specialized for
<code class="sourceCode default">when_all_t</code> as follows:</p>
<blockquote>
<div class="sourceCode" id="cb75"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb75-1"><a href="#cb75-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb75-2"><a href="#cb75-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb75-3"><a href="#cb75-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> <em><code class="sourceCode default">impls-for</code></em><span class="op">&lt;</span>when_all_t<span class="op">&gt;</span> <span class="op">:</span> <em><code class="sourceCode default">default-impls</code></em> <span class="op">{</span></span>
<span id="cb75-4"><a href="#cb75-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-attrs</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb75-5"><a href="#cb75-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-env</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb75-6"><a href="#cb75-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">get-state</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb75-7"><a href="#cb75-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">start</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb75-8"><a href="#cb75-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> <em><code class="sourceCode default">complete</code></em> <span class="op">=</span> <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb75-9"><a href="#cb75-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb75-10"><a href="#cb75-10" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Sndr, class... Env&gt;</code></span></ins></span></span>
<span id="cb75-11"><a href="#cb75-11" aria-hidden="true" tabindex="-1"></a>    <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">check-types</code></em>();</code></span></ins></span></span>
<span id="cb75-12"><a href="#cb75-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb75-13"><a href="#cb75-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="add" style="color: #006e28"><ins>Let
<span><code class="sourceCode default">make-when-all-env</code></span>
be the following exposition-only function template:</ins></span></p>
<blockquote>
<div class="sourceCode" id="cb76"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb76-1"><a href="#cb76-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Env&gt;</span>
<span id="cb76-2"><a href="#cb76-2" aria-hidden="true" tabindex="-1"></a>constexpr auto <em><code class="sourceCode default">make-when-all-env</code></em>(inplace_stop_source&amp; stop_src, Env&amp;&amp; env) noexcept {</span>
<span id="cb76-3"><a href="#cb76-3" aria-hidden="true" tabindex="-1"></a>  return <em><code class="sourceCode default">see below</code></em>;</span>
<span id="cb76-4"><a href="#cb76-4" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
</blockquote>
</blockquote>

</div>
<blockquote>
<p><span style="color:blue;font-style:italic">The following itemized
list has been moved here unmodified from para 6.</span> Returns an
object <code class="sourceCode default">e</code> such that</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<code class="sourceCode default">decltype(e)</code> models
<code class="sourceCode default">queryable</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.2)</a></span>
<code class="sourceCode default">e.query(get_stop_token)</code> is
expression-equivalent to
<code class="sourceCode default">stop_src.get_token()</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.3)</a></span>
given a query object <code class="sourceCode default">q</code> with type
other than <em>cv</em>
<code class="sourceCode default">stop_token_t</code>,
<code class="sourceCode default">e.query(q)</code> is
expression-equivalent to
<code class="sourceCode default">env.query(q)</code>.</p></li>
</ul>
<p><span class="add" style="color: #006e28"><ins>Let
<em><span><code class="sourceCode default">when-all-env</code></span></em>
be an alias template such that
<span><code class="sourceCode default"><em><code class="sourceCode default">when-all-env</code></em>&lt;Env&gt;</code></span>
denotes the type <span><code class="sourceCode default">decltype(<em><code class="sourceCode default">make-when-all-env</code></em>(declval&lt;inplace_stop_source&amp;&gt;(), declval&lt;Env&gt;()))</code></span>.</ins></span></p>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<span class="marginalizedparent"><a class="marginalized">?</a></span>
<div>
<div class="sourceCode" id="cb77"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb77-1"><a href="#cb77-1" aria-hidden="true" tabindex="-1"></a>template&lt;class Sndr, class... Env&gt;</span>
<span id="cb77-2"><a href="#cb77-2" aria-hidden="true" tabindex="-1"></a>static constexpr void <em><code class="sourceCode default">check-types</code></em>();</span></code></pre></div>
</div>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.1)</a></span>
<span class="add" style="color: #006e28"><ins>Let
<span><code class="sourceCode default">Is</code></span> be the pack of
integral template arguments of the
<span><code class="sourceCode default">integer_sequence</code></span>
specialization denoted by
<span><code class="sourceCode default"><em><code class="sourceCode default">indices-for</code></em>&lt;Sndr&gt;</code></span>.</ins></span></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.2)</a></span>
<span class="add" style="color: #006e28"><ins><em>Effects</em>:
Equivalent to:</ins></span></p>
<div class="sourceCode" id="cb78"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb78-1"><a href="#cb78-1" aria-hidden="true" tabindex="-1"></a>auto fn = []&lt;class Child&gt;() {</span>
<span id="cb78-2"><a href="#cb78-2" aria-hidden="true" tabindex="-1"></a>  auto cs = get_completion_signatures&lt;Child, <em><code class="sourceCode default">when-all-env</code></em>&lt;Env&gt;...&gt;();</span>
<span id="cb78-3"><a href="#cb78-3" aria-hidden="true" tabindex="-1"></a>  if constexpr (cs.template <em><code class="sourceCode default">count</code></em>&lt;set_value_t&gt; &gt;= 2)</span>
<span id="cb78-4"><a href="#cb78-4" aria-hidden="true" tabindex="-1"></a>    throw <em><code class="sourceCode default">unspecified</code></em>;</span>
<span id="cb78-5"><a href="#cb78-5" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb78-6"><a href="#cb78-6" aria-hidden="true" tabindex="-1"></a>(fn.template operator()&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr, Is&gt;&gt;(), ...);</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(?.3)</a></span>
<span class="add" style="color: #006e28"><ins><em>Throws</em>: Any
exception thrown as a result of evaluating the <em>Effects</em>, or an
exception of an unspecified type when
<span><code class="sourceCode default">CD</code></span> is
ill-formed.</ins></span></p></li>
</ul>
</blockquote>

</div>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
The member <code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;when_all_t&gt;::<em><code class="sourceCode default">get-attrs</code></em></code>
<span style="color:blue;text-style:italic">… as before …</span></p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
The member <code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;when_all_t&gt;::<em><code class="sourceCode default">get-env</code></em></code>
is initialized with a callable object equivalent to the following lambda
expression:</p>
<blockquote>
<div class="sourceCode" id="cb79"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb79-1"><a href="#cb79-1" aria-hidden="true" tabindex="-1"></a><span class="op">[]&lt;</span><span class="kw">class</span> State, <span class="kw">class</span> Rcvr<span class="op">&gt;(</span><span class="kw">auto</span><span class="op">&amp;&amp;</span>, State<span class="op">&amp;</span> state, <span class="kw">const</span> Receiver<span class="op">&amp;</span> rcvr<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb79-2"><a href="#cb79-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">see below</code></em></code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default"><em><code class="sourceCode default">make-when-all-env</code></em>(state.<em><code class="sourceCode default">stop-src</code></em>, get_env(rcvr))</code></span></ins></span>;</span>
<span id="cb79-3"><a href="#cb79-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</blockquote>
<div class="rm" style="color: #bf0303">

<blockquote>
<p><span class="rm" style="color: #bf0303"><del>Returns an object
<span><code class="sourceCode default">e</code></span> such
that</del></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">decltype(e)</code></span>
models <span><code class="sourceCode default">queryable</code></span>,
and</del></span></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">e.query(get_stop_token)</code></span>
is expression-equivalent to
<span><code class="sourceCode default">state.<em><code class="sourceCode default">stop-src</code></em>.get_token()</code></span>,
and</del></span></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.3)</a></span>
<span class="rm" style="color: #bf0303"><del>given a query object
<span><code class="sourceCode default">q</code></span> with type other
than <em>cv</em>
<span><code class="sourceCode default">stop_token_t</code></span>,
<span><code class="sourceCode default">e.query(q)</code></span> is
expression-equivalent to
<span><code class="sourceCode default">get_env(rcvr).query(q)</code></span>.</del></span></p></li>
</ul>
</blockquote>

</div>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
The member <code class="sourceCode default"><em><code class="sourceCode default">impls-for</code></em>&lt;when_all_t&gt;::<em><code class="sourceCode default">get-state</code></em></code>
is initialized with a callable object equivalent to the following lambda
expression:</p>
<blockquote>
<div class="sourceCode" id="cb80"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb80-1"><a href="#cb80-1" aria-hidden="true" tabindex="-1"></a><span class="op">[]&lt;</span><span class="kw">class</span> Sndr, <span class="kw">class</span> Rcvr<span class="op">&gt;(</span>Sndr<span class="op">&amp;&amp;</span> sndr, Rcvr<span class="op">&amp;</span> rcvr<span class="op">)</span> <span class="kw">noexcept</span><span class="op">(</span><em>e</em><span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><em>e</em><span class="op">)</span> <span class="op">{</span></span>
<span id="cb80-2"><a href="#cb80-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <em>e</em>;</span>
<span id="cb80-3"><a href="#cb80-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>where <em><code class="sourceCode default">e</code></em> is the
expression</p>
<blockquote>
<div class="sourceCode" id="cb81"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb81-1"><a href="#cb81-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>forward<span class="op">&lt;</span>Sndr<span class="op">&gt;(</span>sndr<span class="op">).</span>apply<span class="op">(</span><em><code class="sourceCode default">make-state</code></em><span class="op">&lt;</span>Rcvr<span class="op">&gt;())</span></span></code></pre></div>
</blockquote>
<p>and where <em><code class="sourceCode default">make-state</code></em>
is the following exposition-only class template:</p>
<blockquote>
<div class="sourceCode" id="cb82"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb82-1"><a href="#cb82-1" aria-hidden="true" tabindex="-1"></a><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">template&lt;class Sndr, class Env&gt;</code></span></del></span></span>
<span id="cb82-2"><a href="#cb82-2" aria-hidden="true" tabindex="-1"></a><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">concept <em><code class="sourceCode default">max-1-sender-in</code></em> = sender_in&lt;Sndr, Env&gt; &amp;&amp;</code></span></del></span>                <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">// exposition only</code></span></del></span><span class="op">@</span></span>
<span id="cb82-3"><a href="#cb82-3" aria-hidden="true" tabindex="-1"></a>  <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">(tuple_size_v&lt;value_types_of_t&lt;Sndr, Env, tuple, tuple&gt;&gt; &lt;= 1);</code></span></del></span></span>
<span id="cb82-4"><a href="#cb82-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb82-5"><a href="#cb82-5" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> disposition <span class="op">{</span> started, error, stopped <span class="op">}</span>;             <span class="co">// exposition only</span></span>
<span id="cb82-6"><a href="#cb82-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb82-7"><a href="#cb82-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Rcvr<span class="op">&gt;</span></span>
<span id="cb82-8"><a href="#cb82-8" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> make<span class="op">-</span>state <span class="op">{</span></span>
<span id="cb82-9"><a href="#cb82-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em><code class="sourceCode default">max-1-sender-in</code></em>&lt;env_of_t&lt;Rcvr&gt;&gt;</code></span></del></span><span class="add" style="color: #006e28"><ins>class</ins></span><span class="op">...</span> Sndrs<span class="op">&gt;</span></span>
<span id="cb82-10"><a href="#cb82-10" 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="kw">auto</span>, Sndrs<span class="op">&amp;&amp;...</span> sndrs<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb82-11"><a href="#cb82-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> values_tuple <span class="op">=</span> see below;</span>
<span id="cb82-12"><a href="#cb82-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> errors_variant <span class="op">=</span> see below;</span>
<span id="cb82-13"><a href="#cb82-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> stop_callback <span class="op">=</span> stop_callback_for_t<span class="op">&lt;</span>stop_token_of_t<span class="op">&lt;</span>env_of_t<span class="op">&lt;</span>Rcvr<span class="op">&gt;&gt;</span>, on<span class="op">-</span>stop<span class="op">-</span>request<span class="op">&gt;</span>;</span>
<span id="cb82-14"><a href="#cb82-14" aria-hidden="true" tabindex="-1"></a><span style="color:blue;font-style:italic">… as before …</span></span></code></pre></div>
</blockquote>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.when.all] para 14 as follows: ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span> The
expression
<code class="sourceCode default">when_all_with_variant(sndrs...)</code>
is expression-equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb83"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb83-1"><a href="#cb83-1" aria-hidden="true" tabindex="-1"></a>transform_sender<span class="op">(</span><span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">CD()</code></span></del></span><span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">CD2()</code></span></ins></span>, <em><code class="sourceCode default">make-sender</code></em><span class="op">(</span>when_all_with_variant, <span class="op">{}</span>, sndrs<span class="op">...))</span>;</span></code></pre></div>
</blockquote>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Revert
the change to [exec.stopped.opt] made by P3164R3, and make the following
changes instead. ]</span></p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The name <code class="sourceCode default">stopped_as_optional</code>
denotes a pipeable sender adaptor object. For a subexpression
<code class="sourceCode default">sndr</code>, let
<code class="sourceCode default">Sndr</code> be
<code class="sourceCode default">decltype((sndr))</code>. The expression
<code class="sourceCode default">stopped_as_optional(sndr)</code> is
expression-equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb84"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb84-1"><a href="#cb84-1" aria-hidden="true" tabindex="-1"></a>transform_sender<span class="op">(</span>get<span class="op">-</span>domain<span class="op">-</span>early<span class="op">(</span>sndr<span class="op">)</span>, make<span class="op">-</span>sender<span class="op">(</span>stopped_as_optional, <span class="op">{}</span>, sndr<span class="op">))</span></span></code></pre></div>
</blockquote>
<p>except that <code class="sourceCode default">sndr</code> is only
evaluated once.</p>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="add" style="color: #006e28"><ins>The exposition-only class
template
<em><span><code class="sourceCode default">impls-for</code></span></em>
([exec.snd.general]) is specialized for
<span><code class="sourceCode default">stopped_as_optional_t</code></span>
as follows:</ins></span></p>
<div class="sourceCode" id="cb85"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb85-1"><a href="#cb85-1" aria-hidden="true" tabindex="-1"></a>template&lt;&gt;</span>
<span id="cb85-2"><a href="#cb85-2" aria-hidden="true" tabindex="-1"></a>struct <em><code class="sourceCode default">impls-for</code></em>&lt;stopped_as_optional_t&gt; : <em><code class="sourceCode default">default-impls</code></em> {</span>
<span id="cb85-3"><a href="#cb85-3" aria-hidden="true" tabindex="-1"></a>  template&lt;class Sndr, class... Env&gt;</span>
<span id="cb85-4"><a href="#cb85-4" aria-hidden="true" tabindex="-1"></a>  static constexpr void <em><code class="sourceCode default">check-types</code></em>() {</span>
<span id="cb85-5"><a href="#cb85-5" aria-hidden="true" tabindex="-1"></a>    auto cs = get_completion_signatures&lt;<em><code class="sourceCode default">child-type</code></em>&lt;Sndr&gt;, decltype(<em><code class="sourceCode default">FWD-ENV</code></em>(declval&lt;Env&gt;()))...&gt;();</span>
<span id="cb85-6"><a href="#cb85-6" aria-hidden="true" tabindex="-1"></a>    if constexpr (!requires {typename <em><code class="sourceCode default">single-sender-value-type</code></em>&lt;Sndr, Env...&gt;})</span>
<span id="cb85-7"><a href="#cb85-7" aria-hidden="true" tabindex="-1"></a>      throw <em>unspecified</em>;</span>
<span id="cb85-8"><a href="#cb85-8" aria-hidden="true" tabindex="-1"></a>    else if constexpr (same_as&lt;void, <em><code class="sourceCode default">single-sender-value-type</code></em>&lt;Sndr, Env...&gt;&gt;)</span>
<span id="cb85-9"><a href="#cb85-9" aria-hidden="true" tabindex="-1"></a>      throw <em>unspecified</em>;</span>
<span id="cb85-10"><a href="#cb85-10" aria-hidden="true" tabindex="-1"></a>  }</span>
<span id="cb85-11"><a href="#cb85-11" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>

</div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
Let <code class="sourceCode default">sndr</code> and
<code class="sourceCode default">env</code> be subexpressions such that
<code class="sourceCode default">Sndr</code> is
<code class="sourceCode default">decltype((sndr))</code> and
<code class="sourceCode default">Env</code> is
<code class="sourceCode default">decltype((env))</code>. If <code class="sourceCode default"><em><code class="sourceCode default">sender-for</code></em>&lt;Sndr, stopped_as_optional_t&gt;</code>
is <code class="sourceCode default">false</code><span class="rm" style="color: #bf0303"><del>, or if the type <span><code class="sourceCode default"><em><code class="sourceCode default">single-sender-value-type</code></em>&lt;Sndr, Env&gt;</code></span>
is ill-formed or
<span><code class="sourceCode default">void</code></span>,</del></span>
then the expression <code class="sourceCode default">stopped_as_optional.transform_sender(sndr, env)</code>
is ill-formed; <span class="add" style="color: #006e28"><ins>otherwise,
if <span><code class="sourceCode default"><em><code class="sourceCode default">has-constexpr-completions</code></em>&lt;Sndr, Env&gt;</code></span>
is <span><code class="sourceCode default">false</code></span>, the
expression <span><code class="sourceCode default">stopped_as_optional.transform_sender(sndr, env)</code></span>
is equivalent to
<span><code class="sourceCode default"><em><code class="sourceCode default">not-a-sender</code></em>()</code></span>;</ins></span>
otherwise, it is equivalent to:</p>
<div class="sourceCode" id="cb86"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb86-1"><a href="#cb86-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span><span class="op">&amp;&amp;</span> <span class="op">[</span>_, _, child<span class="op">]</span> <span class="op">=</span> sndr;</span>
<span id="cb86-2"><a href="#cb86-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> V <span class="op">=</span> single<span class="op">-</span>sender<span class="op">-</span>value<span class="op">-</span>type<span class="op">&lt;</span>Sndr, Env<span class="op">&gt;</span>;</span>
<span id="cb86-3"><a href="#cb86-3" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> let_stopped<span class="op">(</span></span>
<span id="cb86-4"><a href="#cb86-4" aria-hidden="true" tabindex="-1"></a>    then<span class="op">(</span>std<span class="op">::</span>forward_like<span class="op">&lt;</span>Sndr<span class="op">&gt;(</span>child<span class="op">)</span>,</span>
<span id="cb86-5"><a href="#cb86-5" aria-hidden="true" tabindex="-1"></a>         <span class="op">[]&lt;</span><span class="kw">class</span><span class="op">...</span> Ts<span class="op">&gt;(</span>Ts<span class="op">&amp;&amp;...</span> ts<span class="op">)</span> <span class="kw">noexcept</span><span class="op">(</span>is_nothrow_constructible_v<span class="op">&lt;</span>V, Ts<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb86-6"><a href="#cb86-6" aria-hidden="true" tabindex="-1"></a>           <span class="cf">return</span> optional<span class="op">&lt;</span>V<span class="op">&gt;(</span>in_place, std<span class="op">::</span>forward<span class="op">&lt;</span>Ts<span class="op">&gt;(</span>ts<span class="op">)...)</span>;</span>
<span id="cb86-7"><a href="#cb86-7" aria-hidden="true" tabindex="-1"></a>         <span class="op">})</span>,</span>
<span id="cb86-8"><a href="#cb86-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">[]()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> just<span class="op">(</span>optional<span class="op">&lt;</span>V<span class="op">&gt;())</span>; <span class="op">})</span>;</span></code></pre></div>
</blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Change
[exec.util.cmplsig] para 8 and add a new para after 8 as follows:
]</span></p>
<blockquote>
<span class="marginalizedparent"><a class="marginalized">8</a></span>
<div>
<div class="sourceCode" id="cb87"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb87-1"><a href="#cb87-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>execution <span class="op">{</span></span>
<span id="cb87-2"><a href="#cb87-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><em><code class="sourceCode default">completion-signature</code></em><span class="op">...</span> Fns<span class="op">&gt;</span></span>
<span id="cb87-3"><a href="#cb87-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> completion_signatures <span class="op">{</span></span>
<span id="cb87-4"><a href="#cb87-4" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Tag&gt;</code></span></ins></span></span>
<span id="cb87-5"><a href="#cb87-5" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr size_t <em><code class="sourceCode default">count</code></em> = <em><code class="sourceCode default">see below</code></em>;</code></span></ins></span></span>
<span id="cb87-6"><a href="#cb87-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-7"><a href="#cb87-7" aria-hidden="true" tabindex="-1"></a>      <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">template&lt;class Fn&gt;</code></span></ins></span></span>
<span id="cb87-8"><a href="#cb87-8" aria-hidden="true" tabindex="-1"></a>        <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">static constexpr void <em><code class="sourceCode default">for-each</code></em>(Fn&amp;&amp; fn) { // exposition only</code></span></ins></span></span>
<span id="cb87-9"><a href="#cb87-9" aria-hidden="true" tabindex="-1"></a>          <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">(std::forward&lt;Fn&gt;(fn)(static_cast&lt;Fns*&gt;(nullptr)), ...);</code></span></ins></span></span>
<span id="cb87-10"><a href="#cb87-10" aria-hidden="true" tabindex="-1"></a>        <span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">}</code></span></ins></span></span>
<span id="cb87-11"><a href="#cb87-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb87-12"><a href="#cb87-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb87-13"><a href="#cb87-13" aria-hidden="true" tabindex="-1"></a>  <span style="color:blue;text-style:italic">… as before …</span></span>
<span id="cb87-14"><a href="#cb87-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
</blockquote>
<div class="add" style="color: #006e28">

<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">?</a></span>
<span class="add" style="color: #006e28"><ins>For a type
<span><code class="sourceCode default">Tag</code></span>, <span><code class="sourceCode default">completion_signatures&lt;Fns...&gt;::count&lt;Tag&gt;</code></span>
is initialized with the count of function types in
<span><code class="sourceCode default">Fns...</code></span> that are of
the form <span><code class="sourceCode default">Tag(Ts...)</code></span>
where <span><code class="sourceCode default">Ts</code></span> is a pack
of types.</ins></span></p>
</blockquote>

</div>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: Remove
subclause [exec.util.cmplsig.trans]. ]</span></p>
<h1 data-number="10" id="proposed-wording-for-the-nice-to-haves"><span class="header-section-number">10</span> Proposed Wording for the
Nice-to-haves<a href="#proposed-wording-for-the-nice-to-haves" class="self-link"></a></h1>
<p><span style="color:blue;font-style:italic">To-Do</span></p>
<h1 data-number="11" id="acknowledgements"><span class="header-section-number">11</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>I would like to thank Hana Dusíková for her work making constexpr
exceptions a reality for C++26. Thanks are also due to David Sankel for
his encouragement to investigate using constexpr exceptions as an
alternative to TMP hackery, and for giving feedback on an early draft of
this paper.</p>
<h1 data-number="12" id="bibliography"><span class="header-section-number">12</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-P2830R7" class="csl-entry" role="doc-biblioentry">
[P2830R7] Gašper Ažman, Nathan Nichols. 2024-11-21. Standardized
Constexpr Type Ordering. <a href="https://wg21.link/p2830r7"><div class="csl-block">https://wg21.link/p2830r7</div></a>
</div>
<div id="ref-P3068R6" class="csl-entry" role="doc-biblioentry">
[P3068R6] Hana Dusíková. 2024-11-19. Allowing exception throwing in
constant-evaluation. <a href="https://wg21.link/p3068r6"><div class="csl-block">https://wg21.link/p3068r6</div></a>
</div>
<div id="ref-P3164R2" class="csl-entry" role="doc-biblioentry">
[P3164R2] Eric Niebler. 2024-06-25. Improving diagnostics for sender
expressions. <a href="https://wg21.link/p3164r2"><div class="csl-block">https://wg21.link/p3164r2</div></a>
</div>
<div id="ref-P3164R3" class="csl-entry" role="doc-biblioentry">
[P3164R3] Eric Niebler. Improving diagnostics for sender expressions. <a href="https://wg21.link/p3164r3"><div class="csl-block">https://wg21.link/p3164r3</div></a>
</div>
</div>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p><a href="https://godbolt.org/z/Y1vPcn6Kr">https://godbolt.org/z/Y1vPcn6Kr</a><a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
