<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P2300R2: `std::execution`</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in § N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *     -> ins/del.c### for candidate and proposed changes (amendments)
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *   - .correction for "candidate corrections"       (div, aside, details, section)
 *   - .addition   for "candidate additions"         (div, aside, details, section)
 *   - .correction.proposed for "proposed corrections" (div, aside, details, section)
 *   - .addition.proposed   for "proposed additions"   (div, aside, details, section)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Outdated warning for old specs
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/* color variables included separately for reliability */

/******************************************************************************/
/*                                    Body                                    */
/******************************************************************************/

	html {
	}

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;			  /* limit line length to 50em for readability   */
		margin: 0 auto;				/* center text within page                    */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag    */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		color: black;
		color: var(--text);
		background: white top left fixed no-repeat;
		background: var(--bg) top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em; }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border: solid var(--logo-bg);
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		background: var(--logo-bg);
		color: white;
		color: var(--logo-text);
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		background: var(--logo-active-bg);
		border-color: #c00;
		border-color: var(--logo-active-bg);
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small; }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 3;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;

			color: #707070;
			color: var(--tocnav-normal-text);
			background: white;
			background: var(--tocnav-normal-bg);
		}
		#toc-nav > a:hover,
		#toc-nav > a:focus {
			color: black;
			color: var(--tocnav-hover-text);
			background: #f8f8f8;
			background: var(--tocnav-hover-bg);
		}
		#toc-nav > a:active {
			color: #c00;
			color: var(--tocnav-active-text);
			background: white;
			background: var(--tocnav-active-bg);
		}

		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;	/* Inherit the font family. */
		line-height: 1.2;		/* Keep wrapped headings compact */
		hyphens: manual;		/* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		color: var(--heading-text);
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#profile-and-date {
		/* #profile-and-date is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > :not(.head) + hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		color: black;
		color: var(--hr-text);
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	border-left: 0.5em solid #DEF;
	border-left: 0.5em solid var(--algo-border);
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	 padding: .5em;
	 border: thin solid #ddd;
	 border: thin solid var(--algo-border);
	 border-radius: .5em;
	 margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	 margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	 margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	margin-left: -2em;
	}
	dl.switch {
	padding-left: 2em;
	}
	dl.switch > dt {
	text-indent: -1.5em;
	margin-top: 1em;
	}
	dl.switch > dt + dt {
	margin-top: 0;
	}
	dl.switch > dt::before {
	content: '\21AA';
	padding: 0 0.5em 0 0;
	display: inline-block;
	width: 1em;
	text-align: right;
	line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: inherit;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del {
		color: #aa0000;
		color: var(--del-text);
		background: transparent;
		background: var(--del-bg);
		text-decoration: line-through;
	}
	ins {
		color: #006100;
		color: var(--ins-text);
		background: transparent;
		background: var(--ins-bg);
		text-decoration: underline;
	}

	/* for amendments (candidate/proposed changes) */

	.amendment ins, .correction ins, .addition ins,
	ins[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment del, .correction del, .addition del,
	del[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment.proposed ins, .correction.proposed ins, .addition.proposed ins,
	ins[class^=c].proposed {
		text-decoration-style: double;
	}
	.amendment.proposed del, .correction.proposed del, .addition.proposed del,
	del[class^=c].proposed {
		text-decoration-style: double;
	}

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		hyphens: none;
		text-transform: none;
		text-align: left;
		text-align: start;
		font-variant: normal;
		orphans: 3;
		widows: 3;
		page-break-before: avoid;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

	/* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		color: var(--a-normal-text);
		text-decoration: underline #707070;
		text-decoration: underline var(--a-normal-underline);
		text-decoration-skip-ink: none;
	}
	a:visited {
		color: #034575;
		color: var(--a-visited-text);
		text-decoration-color: #bbb;
		text-decoration-color: var(--a-visited-underline);
	}

	/* Indicate interaction with the link */
	a[href]:focus,
	a[href]:hover {
		text-decoration-thickness: 2px;
	}
	a[href]:active {
		color: #c00;
		color: var(--a-active-text);
		text-decoration-color: #c00;
		text-decoration-color: var(--a-active-underline);
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	img, svg {
		/* Intentionally not color-scheme aware. */
		background: white;
	}

	/* For autogen numbers, add
	  .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,	.sidefigure img,	figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
		height: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em;
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em; }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote,
	.amendment, .correction, .addition {
		margin: 1em auto;
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	blockquote > :first-child,
	.note  > p:first-child,
	.issue > p:first-child,
	.amendment > p:first-child,
	.correction > p:first-child,
	.addition > p:first-child {
		margin-top: 0;
	}
	blockquote > :last-child,
	.note  > p:last-child,
	.issue > p:last-child,
	.amendment > p:last-child,
	.correction > p:last-child,
	.addition > p:last-child {
		margin-bottom: 0;
	}


	.issue::before, .issue > .marker,
	.example::before, .example > .marker,
	.note::before, .note > .marker,
	details.note > summary > .marker,
	.amendment::before, .amendment > .marker,
	details.amendment > summary > .marker,
	.addition::before, .addition > .marker,
	addition.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	correction.amendment > summary > .marker
	{
		text-transform: uppercase;
		padding-right: 1em;
	}

	.example::before, .example > .marker {
		display: block;
		padding-right: 0em;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
		border-color: var(--blockquote-border);
		background: transparent;
		background: var(--blockquote-bg);
		color: currentcolor;
		color: var(--blockquote-text);
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #e05252;
		border-color: var(--issue-border);
		background: #fbe9e9;
		background: var(--issue-bg);
		color: black;
		color: var(--issue-text);
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		color: #831616;
		color: var(--issueheading-text);
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	  or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #e0cb52;
		border-color: var(--example-border);
		background: #fcfaee;
		background: var(--example-bg);
		color: black;
		color: var(--example-text);
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		color: #574b0f;
		color: var(--exampleheading-text);
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	  or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52e052;
		border-color: var(--note-border);
		background: #e9fbe9;
		background: var(--note-bg);
		color: black;
		color: var(--note-text);
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary {
		color: hsl(120, 70%, 30%);
		color: var(--noteheading-text);
	}
	/* Add .note::before { content: "Note "; } for autogen label,
	  or use class="marker" to mark up the label in source. */

	details.note[open] > summary {
		border-bottom: 1px silver solid;
		border-bottom: 1px var(--notesummary-underline) solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		border-color: var(--assertion-border);
		background: #EEE;
		background: var(--assertion-bg);
		color: black;
		color: var(--assertion-text);
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-color: var(--advisement-border);
		border-style: none solid;
		background: #fec;
		background: var(--advisement-bg);
		color: black;
		color: var(--advisement-text);
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement::before, .advisement > .marker {
		color: #b35f00;
		color: var(--advisementheading-text);
	}

/** Amendment Box *************************************************************/

	.amendment, .correction, .addition {
		border-color: #330099;
		border-color: var(--amendment-border);
		background: #F5F0FF;
		background: var(--amendment-bg);
		color: black;
		color: var(--amendment-text);
	}
	.amendment.proposed, .correction.proposed, .addition.proposed {
		border-style: solid;
		border-block-width: 0.25em;
	}
	.amendment::before, .amendment > .marker,
	details.amendment > summary::before, details.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	details.correction > summary::before, details.correction > summary > .marker,
	.addition::before, .addition > .marker,
	details.addition > summary::before, details.addition > summary > .marker {
		color: #220066;
		color: var(--amendmentheading-text);
	}
	.amendment.proposed::before, .amendment.proposed > .marker,
	details.amendment.proposed > summary::before, details.amendment.proposed > summary > .marker,
	.correction.proposed::before, .correction.proposed > .marker,
	details.correction.proposed > summary::before, details.correction.proposed > summary > .marker,
	.addition.proposed::before, .addition.proposed > .marker,
	details.addition.proposed > summary::before, details.addition.proposed > summary > .marker {
		font-weight: bold;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: hsla(40,100%,50%,0.95);
		background: var(--warning-bg);
		color: black;
		color: var(--warning-text);
		padding: .75em 1em;
		border: red;
		border: var(--warning-border);
		border-style: solid none;
		box-shadow: 0 2px 8px black;
		text-align: center;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 2em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #def;
		background: var(--def-bg);
		margin: 1.2em 0;
		border-left: 0.5em solid #8ccbf2;
		border-left: 0.5em solid var(--def-border);
		color: black;
		color: var(--def-text);
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
		border-bottom: 1px solid var(--defrow-border);
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def td.footnote {
		padding-top: 0.6em;
	}
	table.def td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		<table class="data"> highlights structural relationships in a table
		when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		Use class="complex data" for particularly complicated tables --
		(This will draw more lines: busier, but clearer.)

		Use class="long" on table cells with paragraph-like contents
		(This will adjust text alignment accordingly.)
		Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-color: var(--datacell-border);
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		border-top: 1px solid var(--datacell-border);
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		border: 1px solid var(--datacell-border);
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
		vertical-align: baseline;
		text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding: 0.1rem 1px 0;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Switch to using border-bottom for underlines */
		text-decoration: none;
		border-bottom: 1px solid;
		/* Reverse color scheme */
		color: black;
		color: var(--toclink-text);
		border-color: #3980b5;
		border-color: var(--toclink-underline);
	}
	.toc a:visited {
		color: black;
		color: var(--toclink-visited-text);
		border-color: #054572;
		border-color: var(--toclink-visited-underline);
	}
	.toc a:focus,
	.toc a:hover {
		background: rgba(75%, 75%, 75%, .25);
		background: var(--a-hover-bg);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
	}
	.toc {
		line-height: 1.1em;
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li			{ font-weight: bold;   }
	.toc > li li		 { font-weight: normal; }
	.toc > li li li	  { font-size:   95%;	}
	.toc > li li li li	{ font-size:   90%;	}
	.toc > li li li li li { font-size:   85%;	}

	/* @supports not (display:grid) { */
		.toc > li			{ margin: 1.5rem 0;	}
		.toc > li li		 { margin: 0.3rem 0;	}
		.toc > li li li	  { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}
		.toc > li li li li .secno { font-size: 85%; }
		.toc > li li li li li .secno { font-size: 100%; }

		.toc li {
			clear: both;
		}

		:not(li) > .toc			 { margin-left:  5rem; }
		.toc .secno				 { margin-left: -5rem; }
		.toc > li li li .secno	  { margin-left: -7rem; }
		.toc > li li li li .secno	{ margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc			 { margin-left:  4rem; }
			.toc .secno				 { margin-left: -4rem; }
			.toc > li li li			 { margin-left:  1rem; }
			.toc > li li li .secno	  { margin-left: -5rem; }
			.toc > li li li li .secno	{ margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
		/* Loosen it on wide screens */
		@media screen and (min-width: 78em) {
			body:not(.toc-inline) :not(li) > .toc			 { margin-left:  4rem; }
			body:not(.toc-inline) .toc .secno				 { margin-left: -4rem; }
			body:not(.toc-inline) .toc > li li li			 { margin-left:  1rem; }
			body:not(.toc-inline) .toc > li li li .secno	  { margin-left: -5rem; }
			body:not(.toc-inline) .toc > li li li li .secno	{ margin-left: -6rem; }
			body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	/* } */

	@supports (display:grid) and (display:contents) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			  comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
		}
		#toc .content:hover,
		#toc .content:focus {
			background: rgba(75%, 75%, 75%, .25);
			background: var(--a-hover-bg);
			border-bottom: 3px solid #054572;
			border-bottom: 3px solid var(--toclink-underline);
			margin-bottom: -3px;
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index	  { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li	{ margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em; }
	ul.index dl	{ margin-top: 0; }
	ul.index dt	{ margin: .2em 0 .2em 20px;}
	ul.index dd	{ margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li span:not(.dfn-paneled) {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
			color: var(--indexinfo-text);
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		color: black;
		color: var(--indextable-hover-text);
		background: #f7f8f9;
		background: var(--indextable-hover-bg);
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/** Outdated warning **********************************************************/

.outdated-spec {
	color: black;
	color: var(--outdatedspec-text);
	background-color: rgba(0,0,0,0.5);
	background-color: var(--outdatedspec-bg);
}

.outdated-warning {
	position: fixed;
	bottom: 50%;
	left: 0;
	right: 0;
	margin: 0 auto;
	width: 50%;
	background: maroon;
	background: var(--outdated-bg);
	color: white;
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	position: absolute;
	top: 0;
	right:0;
	margin: 0;
	border: 0;
	padding: 0.25em 0.5em;
	background: transparent;
	color: white;
	color: var(--outdated-text);
	font:1em sans-serif;
	text-align:center;
}

.outdated-warning span {
	display: block;
}

.outdated-collapsed {
	bottom: 0;
	border-radius: 0;
	width: 100%;
	padding: 0;
}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}

		.outdated-warning {
			position: absolute;
			border-style: solid;
			border-color: red;
		}

		.outdated-warning input {
			display: none;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge {
		/* Magic to create good item positioning:
		  "content column" is 50ems wide at max; less on smaller screens.
		  Extra space (after ToC + content) is empty on the right.

		  1. When item < content column, centers item in column.
		  2. When content < item < available, left-aligns.
		  3. When item > available, fills available + scroll bar.
		*/
		display: grid;
		grid-template-columns: minmax(0, 50em);
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			* http://lea.verou.me/2012/04/background-attachment-local/
			*
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
						top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
						top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style type="text/css">
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }

    del { background: #fcc; color: #000; text-decoration: line-through; }
    ins { background: #cfc; color: #000; }
    blockquote .highlight:not(.idl) { background: initial; margin: initial; padding: 0.5em }
    blockquote ul { background: inherit; }
    blockquote code.highlight:not(.idl) { padding: initial; }
    blockquote c-[a] { color: inherit; } /* Keyword.Declaration */
    blockquote c-[b] { color: inherit; } /* Keyword.Type */
    blockquote c-[c] { color: inherit; } /* Comment */
    blockquote c-[d] { color: inherit; } /* Comment.Multiline */
    blockquote c-[e] { color: inherit; } /* Name.Attribute */
    blockquote c-[f] { color: inherit; } /* Name.Tag */
    blockquote c-[g] { color: inherit; } /* Name.Variable */
    blockquote c-[k] { color: inherit; } /* Keyword */
    blockquote c-[l] { color: inherit; } /* Literal */
    blockquote c-[m] { color: inherit; } /* Literal.Number */
    blockquote c-[n] { color: inherit; } /* Name */
    blockquote c-[o] { color: inherit; } /* Operator */
    blockquote c-[p] { color: inherit; } /* Punctuation */
    blockquote c-[s] { color: inherit; } /* Literal.String */
    blockquote c-[t] { color: inherit; } /* Literal.String.Single */
    blockquote c-[u] { color: inherit; } /* Literal.String.Double */
    blockquote c-[cp] { color: inherit; } /* Comment.Preproc */
    blockquote c-[c1] { color: inherit; } /* Comment.Single */
    blockquote c-[cs] { color: inherit; } /* Comment.Special */
    blockquote c-[kc] { color: inherit; } /* Keyword.Constant */
    blockquote c-[kn] { color: inherit; } /* Keyword.Namespace */
    blockquote c-[kp] { color: inherit; } /* Keyword.Pseudo */
    blockquote c-[kr] { color: inherit; } /* Keyword.Reserved */
    blockquote c-[ld] { color: inherit; } /* Literal.Date */
    blockquote c-[nc] { color: inherit; } /* Name.Class */
    blockquote c-[no] { color: inherit; } /* Name.Constant */
    blockquote c-[nd] { color: inherit; } /* Name.Decorator */
    blockquote c-[ni] { color: inherit; } /* Name.Entity */
    blockquote c-[ne] { color: inherit; } /* Name.Exception */
    blockquote c-[nf] { color: inherit; } /* Name.Function */
    blockquote c-[nl] { color: inherit; } /* Name.Label */
    blockquote c-[nn] { color: inherit; } /* Name.Namespace */
    blockquote c-[py] { color: inherit; } /* Name.Property */
    blockquote c-[ow] { color: inherit; } /* Operator.Word */
    blockquote c-[mb] { color: inherit; } /* Literal.Number.Bin */
    blockquote c-[mf] { color: inherit; } /* Literal.Number.Float */
    blockquote c-[mh] { color: inherit; } /* Literal.Number.Hex */
    blockquote c-[mi] { color: inherit; } /* Literal.Number.Integer */
    blockquote c-[mo] { color: inherit; } /* Literal.Number.Oct */
    blockquote c-[sb] { color: inherit; } /* Literal.String.Backtick */
    blockquote c-[sc] { color: inherit; } /* Literal.String.Char */
    blockquote c-[sd] { color: inherit; } /* Literal.String.Doc */
    blockquote c-[se] { color: inherit; } /* Literal.String.Escape */
    blockquote c-[sh] { color: inherit; } /* Literal.String.Heredoc */
    blockquote c-[si] { color: inherit; } /* Literal.String.Interpol */
    blockquote c-[sx] { color: inherit; } /* Literal.String.Other */
    blockquote c-[sr] { color: inherit; } /* Literal.String.Regex */
    blockquote c-[ss] { color: inherit; } /* Literal.String.Symbol */
    blockquote c-[vc] { color: inherit; } /* Name.Variable.Class */
    blockquote c-[vg] { color: inherit; } /* Name.Variable.Global */
    blockquote c-[vi] { color: inherit; } /* Name.Variable.Instance */
    blockquote c-[il] { color: inherit; } /* Literal.Number.Integer.Long */
  </style>
  <meta content="Bikeshed version a210b7d86, updated Thu Sep 16 13:45:19 2021 -0700" name="generator">
  <link href="https://wg21.link/P2300" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<style>
pre {
  margin-top: 0px;
  margin-bottom: 0px;
}
table, th, tr, td {
  border: 2px solid black !important;
}
@media (prefers-color-scheme: dark) {
  table, th, tr, td {
    border: 2px solid white !important;
  }
}
.ins, ins, ins *, span.ins, span.ins * {
  background-color: rgb(200, 250, 200);
  color: rgb(0, 136, 0);
  text-decoration: none;
}
.del, del, del *, span.del, span.del * {
  background-color: rgb(250, 200, 200);
  color: rgb(255, 0, 0);
  text-decoration: line-through;
  text-decoration-color: rgb(255, 0, 0);
}
math, span.math {
  font-family: serif;
  font-style: italic;
}
ul {
  list-style-type: "— ";
}
blockquote {
  counter-reset: paragraph;
}
div.numbered, div.newnumbered {
  margin-left: 2em;
  margin-top: 1em;
  margin-bottom: 1em;
}
div.numbered:before, div.newnumbered:before {
  position: absolute;
  margin-left: -2em;
  display-style: block;
}
div.numbered:before {
  content: counter(paragraph);
  counter-increment: paragraph;
}
div.newnumbered:before {
  content: "�";
}
div.numbered ul, div.newnumbered ul {
  counter-reset: list_item;
}
div.numbered li, div.newnumbered li {
  margin-left: 3em;
}
div.numbered li:before, div.newnumbered li:before {
  position: absolute;
  margin-left: -4.8em;
  display-style: block;
}
div.numbered li:before {
  content: "(" counter(paragraph) "." counter(list_item) ")";
  counter-increment: list_item;
}
div.newnumbered li:before {
  content: "(�." counter(list_item) ")";
  counter-increment: list_item;
}
</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: var(--a-normal-text);
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}</style>
<style>/* style-colors */

/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */
:root {
    color-scheme: light dark;

    --text: black;
    --bg: white;

    --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark);

    --logo-bg: #1a5e9a;
    --logo-active-bg: #c00;
    --logo-text: white;

    --tocnav-normal-text: #707070;
    --tocnav-normal-bg: var(--bg);
    --tocnav-hover-text: var(--tocnav-normal-text);
    --tocnav-hover-bg: #f8f8f8;
    --tocnav-active-text: #c00;
    --tocnav-active-bg: var(--tocnav-normal-bg);

    --tocsidebar-text: var(--text);
    --tocsidebar-bg: #f7f8f9;
    --tocsidebar-shadow: rgba(0,0,0,.1);
    --tocsidebar-heading-text: hsla(203,20%,40%,.7);

    --toclink-text: var(--text);
    --toclink-underline: #3980b5;
    --toclink-visited-text: var(--toclink-text);
    --toclink-visited-underline: #054572;

    --heading-text: #005a9c;

    --hr-text: var(--text);

    --algo-border: #def;

    --del-text: red;
    --del-bg: transparent;
    --ins-text: #080;
    --ins-bg: transparent;

    --a-normal-text: #034575;
    --a-normal-underline: #bbb;
    --a-visited-text: var(--a-normal-text);
    --a-visited-underline: #707070;
    --a-hover-bg: rgba(75%, 75%, 75%, .25);
    --a-active-text: #c00;
    --a-active-underline: #c00;

    --blockquote-border: silver;
    --blockquote-bg: transparent;
    --blockquote-text: currentcolor;

    --issue-border: #e05252;
    --issue-bg: #fbe9e9;
    --issue-text: var(--text);
    --issueheading-text: #831616;

    --example-border: #e0cb52;
    --example-bg: #fcfaee;
    --example-text: var(--text);
    --exampleheading-text: #574b0f;

    --note-border: #52e052;
    --note-bg: #e9fbe9;
    --note-text: var(--text);
    --noteheading-text: hsl(120, 70%, 30%);
    --notesummary-underline: silver;

    --assertion-border: #aaa;
    --assertion-bg: #eee;
    --assertion-text: black;

    --advisement-border: orange;
    --advisement-bg: #fec;
    --advisement-text: var(--text);
    --advisementheading-text: #b35f00;

    --warning-border: red;
    --warning-bg: hsla(40,100%,50%,0.95);
    --warning-text: var(--text);

    --amendment-border: #330099;
    --amendment-bg: #F5F0FF;
    --amendment-text: var(--text);
    --amendmentheading-text: #220066;

    --def-border: #8ccbf2;
    --def-bg: #def;
    --def-text: var(--text);
    --defrow-border: #bbd7e9;

    --datacell-border: silver;

    --indexinfo-text: #707070;

    --indextable-hover-text: black;
    --indextable-hover-bg: #f7f8f9;

    --outdatedspec-bg: rgba(0, 0, 0, .5);
    --outdatedspec-text: black;
    --outdated-bg: maroon;
    --outdated-text: white;
    --outdated-shadow: red;

    --editedrec-bg: darkorange;
}</style>
<style>/* style-counters */

body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}</style>
<style>/* style-dfn-panel */

:root {
    --dfnpanel-bg: #ddd;
    --dfnpanel-text: var(--text);
}
.dfn-panel {
    position: absolute;
    z-index: 35;
    height: auto;
    width: -webkit-fit-content;
    width: fit-content;
    max-width: 300px;
    max-height: 500px;
    overflow: auto;
    padding: 0.5em 0.75em;
    font: small Helvetica Neue, sans-serif, Droid Sans Fallback;
    background: var(--dfnpanel-bg);
    color: var(--dfnpanel-text);
    border: outset 0.2em;
}
.dfn-panel:not(.on) { display: none; }
.dfn-panel * { margin: 0; padding: 0; text-indent: 0; }
.dfn-panel > b { display: block; }
.dfn-panel a { color: var(--dfnpanel-text); }
.dfn-panel a:not(:hover) { text-decoration: none !important; border-bottom: none !important; }
.dfn-panel > b + b { margin-top: 0.25em; }
.dfn-panel ul { padding: 0; }
.dfn-panel li { list-style: inside; }
.dfn-panel.activated {
    display: inline-block;
    position: fixed;
    left: .5em;
    bottom: 2em;
    margin: 0 auto;
    max-width: calc(100vw - 1.5em - .4em - .5em);
    max-height: 30vh;
}

.dfn-paneled { cursor: pointer; }
</style>
<style>/* style-issues */

a[href].issue-return {
    float: right;
    float: inline-end;
    color: var(--issueheading-text);
    font-weight: bold;
    text-decoration: none;
}
</style>
<style>/* style-md-lists */

/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}</style>
<style>/* style-selflinks */

:root {
    --selflink-text: white;
    --selflink-bg: gray;
    --selflink-hover-text: black;
}
.heading, .issue, .note, .example, li, dt {
    position: relative;
}
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;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: var(--selflink-bg);
    color: var(--selflink-text);
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: var(--selflink-hover-text);
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }
</style>
<style>/* style-syntax-highlighting */

code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }

.highlight:not(.idl) { background: rgba(0, 0, 0, .03); }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-darkmode */

@media (prefers-color-scheme: dark) {
    :root {
        --text: #ddd;
        --bg: black;

        --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E");

        --logo-bg: #1a5e9a;
        --logo-active-bg: #c00;
        --logo-text: white;

        --tocnav-normal-text: #999;
        --tocnav-normal-bg: var(--bg);
        --tocnav-hover-text: var(--tocnav-normal-text);
        --tocnav-hover-bg: #080808;
        --tocnav-active-text: #f44;
        --tocnav-active-bg: var(--tocnav-normal-bg);

        --tocsidebar-text: var(--text);
        --tocsidebar-bg: #080808;
        --tocsidebar-shadow: rgba(255,255,255,.1);
        --tocsidebar-heading-text: hsla(203,20%,40%,.7);

        --toclink-text: var(--text);
        --toclink-underline: #6af;
        --toclink-visited-text: var(--toclink-text);
        --toclink-visited-underline: #054572;

        --heading-text: #8af;

        --hr-text: var(--text);

        --algo-border: #456;

        --del-text: #f44;
        --del-bg: transparent;
        --ins-text: #4a4;
        --ins-bg: transparent;

        --a-normal-text: #6af;
        --a-normal-underline: #555;
        --a-visited-text: var(--a-normal-text);
        --a-visited-underline: var(--a-normal-underline);
        --a-hover-bg: rgba(25%, 25%, 25%, .2);
        --a-active-text: #f44;
        --a-active-underline: var(--a-active-text);

        --borderedblock-bg: rgba(255, 255, 255, .05);

        --blockquote-border: silver;
        --blockquote-bg: var(--borderedblock-bg);
        --blockquote-text: currentcolor;

        --issue-border: #e05252;
        --issue-bg: var(--borderedblock-bg);
        --issue-text: var(--text);
        --issueheading-text: hsl(0deg, 70%, 70%);

        --example-border: hsl(50deg, 90%, 60%);
        --example-bg: var(--borderedblock-bg);
        --example-text: var(--text);
        --exampleheading-text: hsl(50deg, 70%, 70%);

        --note-border: hsl(120deg, 100%, 35%);
        --note-bg: var(--borderedblock-bg);
        --note-text: var(--text);
        --noteheading-text: hsl(120, 70%, 70%);
        --notesummary-underline: silver;

        --assertion-border: #444;
        --assertion-bg: var(--borderedblock-bg);
        --assertion-text: var(--text);

        --advisement-border: orange;
        --advisement-bg: #222218;
        --advisement-text: var(--text);
        --advisementheading-text: #f84;

        --warning-border: red;
        --warning-bg: hsla(40,100%,20%,0.95);
        --warning-text: var(--text);

        --amendment-border: #330099;
        --amendment-bg: #080010;
        --amendment-text: var(--text);
        --amendmentheading-text: #cc00ff;

        --def-border: #8ccbf2;
        --def-bg: #080818;
        --def-text: var(--text);
        --defrow-border: #136;

        --datacell-border: silver;

        --indexinfo-text: #aaa;

        --indextable-hover-text: var(--text);
        --indextable-hover-bg: #181818;

        --outdatedspec-bg: rgba(255, 255, 255, .5);
        --outdatedspec-text: black;
        --outdated-bg: maroon;
        --outdated-text: white;
        --outdated-shadow: red;

        --editedrec-bg: darkorange;
    }
    /* In case a transparent-bg image doesn't expect to be on a dark bg,
       which is quite common in practice... */
    img { background: white; }
}
@media (prefers-color-scheme: dark) {
    :root {
        --selflink-text: black;
        --selflink-bg: silver;
        --selflink-hover-text: white;
    }
}

@media (prefers-color-scheme: dark) {
    .highlight:not(.idl) { background: rgba(255, 255, 255, .05); }

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P2300R2<br><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-></code></h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal, <time class="dt-updated" datetime="2021-10-04">2021-10-04</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt class="editor">Authors:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:griwes@griwes.info">Michał Dominiak</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:lewissbaker@gmail.com">Lewis Baker</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:xrikcus@gmail.com">Lee Howes</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:kirk.shoop@gmail.com">Kirk Shoop</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:mgarland@nvidia.com">Michael Garland</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:eric.niebler@gmail.com">Eric Niebler</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:brycelelbach@gmail.com">Bryce Adelstein Lelbach</a>
     <dt>Source:
     <dd><a href="https://github.com/brycelelbach/wg21_p2300_std_execution/blob/main/std_execution.bs">GitHub</a>
     <dt>Issue Tracking:
     <dd><a href="https://github.com/brycelelbach/wg21_p2300_std_execution/issues">GitHub</a>
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
     <dt>Audience:
     <dd>SG1, LEWG
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#intro"><span class="secno">1</span> <span class="content">Introduction</span></a>
     <ol class="toc">
      <li><a href="#motivation"><span class="secno">1.1</span> <span class="content">Motivation</span></a>
      <li><a href="#priorities"><span class="secno">1.2</span> <span class="content">Priorities</span></a>
      <li>
       <a href="#example-end-user"><span class="secno">1.3</span> <span class="content">Examples: End User</span></a>
       <ol class="toc">
        <li><a href="#example-hello-world"><span class="secno">1.3.1</span> <span class="content">Hello world</span></a>
        <li><a href="#example-async-inclusive-scan"><span class="secno">1.3.2</span> <span class="content">Asynchronous inclusive scan</span></a>
        <li><a href="#example-async-dynamically-sized-read"><span class="secno">1.3.3</span> <span class="content">Asynchronous dynamically-sized read</span></a>
        <li>
         <a href="#example-moar"><span class="secno">1.3.4</span> <span class="content">More end-user examples</span></a>
         <ol class="toc">
          <li><a href="#example-sudoku"><span class="secno">1.3.4.1</span> <span class="content">Sudoku solver</span></a>
          <li><a href="#example-file-copy"><span class="secno">1.3.4.2</span> <span class="content">File copy</span></a>
          <li><a href="#example-echo-server"><span class="secno">1.3.4.3</span> <span class="content">Echo server</span></a>
         </ol>
       </ol>
      <li>
       <a href="#example-algorithm"><span class="secno">1.4</span> <span class="content">Examples: Algorithms</span></a>
       <ol class="toc">
        <li><a href="#example-then"><span class="secno">1.4.1</span> <span class="content"><code class="highlight"><c- n>then</c-></code></span></a>
        <li><a href="#example-retry"><span class="secno">1.4.2</span> <span class="content"><code class="highlight"><c- n>retry</c-></code></span></a>
       </ol>
      <li>
       <a href="#example-schedulers"><span class="secno">1.5</span> <span class="content">Examples: Schedulers</span></a>
       <ol class="toc">
        <li><a href="#example-schedulers-inline"><span class="secno">1.5.1</span> <span class="content">Inline scheduler</span></a>
        <li><a href="#example-single-thread"><span class="secno">1.5.2</span> <span class="content">Single thread scheduler</span></a>
       </ol>
      <li><a href="#intro-is-not"><span class="secno">1.6</span> <span class="content">What this proposal is <strong>not</strong></span></a>
      <li><a href="#intro-compare"><span class="secno">1.7</span> <span class="content">Design changes from P0443</span></a>
      <li>
       <a href="#intro-prior-art"><span class="secno">1.8</span> <span class="content">Prior art</span></a>
       <ol class="toc">
        <li><a href="#intro-prior-art-futures"><span class="secno">1.8.1</span> <span class="content">Futures</span></a>
        <li><a href="#intro-prior-art-coroutines"><span class="secno">1.8.2</span> <span class="content">Coroutines</span></a>
        <li><a href="#intro-prior-art-callbacks"><span class="secno">1.8.3</span> <span class="content">Callbacks</span></a>
       </ol>
      <li><a href="#intro-field-experience"><span class="secno">1.9</span> <span class="content">Field experience</span></a>
     </ol>
    <li>
     <a href="#revisions"><span class="secno">2</span> <span class="content">Revision history</span></a>
     <ol class="toc">
      <li><a href="#r2"><span class="secno">2.1</span> <span class="content">R2</span></a>
      <li><a href="#r1"><span class="secno">2.2</span> <span class="content">R1</span></a>
      <li><a href="#r0"><span class="secno">2.3</span> <span class="content">R0</span></a>
     </ol>
    <li>
     <a href="#design-intro"><span class="secno">3</span> <span class="content">Design - introduction</span></a>
     <ol class="toc">
      <li><a href="#design-conventions"><span class="secno">3.1</span> <span class="content">Conventions</span></a>
      <li><a href="#design-queries-and-algorithms"><span class="secno">3.2</span> <span class="content">Queries and algorithms</span></a>
     </ol>
    <li>
     <a href="#design-user"><span class="secno">4</span> <span class="content">Design - user side</span></a>
     <ol class="toc">
      <li><a href="#design-contexts"><span class="secno">4.1</span> <span class="content">Execution contexts describe the place of execution</span></a>
      <li><a href="#design-schedulers"><span class="secno">4.2</span> <span class="content">Schedulers represent execution contexts</span></a>
      <li><a href="#design-senders"><span class="secno">4.3</span> <span class="content">Senders describe work</span></a>
      <li><a href="#design-composable"><span class="secno">4.4</span> <span class="content">Senders are composable through sender algorithms</span></a>
      <li>
       <a href="#design-propagation"><span class="secno">4.5</span> <span class="content">Senders can propagate completion schedulers</span></a>
       <ol class="toc">
        <li><a href="#design-sender-query-get_completion_scheduler"><span class="secno">4.5.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code></span></a>
       </ol>
      <li><a href="#design-transitions"><span class="secno">4.6</span> <span class="content">Execution context transitions are explicit</span></a>
      <li><a href="#design-shot"><span class="secno">4.7</span> <span class="content">Senders can be either multi-shot or single-shot</span></a>
      <li><a href="#design-forkable"><span class="secno">4.8</span> <span class="content">Senders are forkable</span></a>
      <li><a href="#design-join"><span class="secno">4.9</span> <span class="content">Senders are joinable</span></a>
      <li>
       <a href="#design-cancellation"><span class="secno">4.10</span> <span class="content">Senders support cancellation</span></a>
       <ol class="toc">
        <li><a href="#design-cancellation-summary"><span class="secno">4.10.1</span> <span class="content">Cancellation design summary</span></a>
        <li><a href="#design-cancellation-optional"><span class="secno">4.10.2</span> <span class="content">Support for cancellation is optional</span></a>
        <li><a href="#design-cancellation-racy"><span class="secno">4.10.3</span> <span class="content">Cancellation is inherently racy</span></a>
        <li><a href="#design-cancellation-status"><span class="secno">4.10.4</span> <span class="content">Cancellation design status</span></a>
       </ol>
      <li><a href="#design-fpg"><span class="secno">4.11</span> <span class="content">Schedulers advertise their forward progress guarantees</span></a>
      <li><a href="#design-pipeable"><span class="secno">4.12</span> <span class="content">Most sender adaptors are pipeable</span></a>
      <li><a href="#design-range-of-senders"><span class="secno">4.13</span> <span class="content">A range of senders represents an async sequence of data</span></a>
      <li><a href="#design-partial-success"><span class="secno">4.14</span> <span class="content">Senders can represent partial success</span></a>
      <li><a href="#design-awaitables-are-senders"><span class="secno">4.15</span> <span class="content">All awaitables are senders</span></a>
      <li><a href="#design-senders-are-awaitable"><span class="secno">4.16</span> <span class="content">Many senders can be trivially made awaitable</span></a>
      <li><a href="#design-native-coro-unwind"><span class="secno">4.17</span> <span class="content">Cancellation of a sender can unwind a stack of coroutines</span></a>
      <li><a href="#design-parallel-algorithms"><span class="secno">4.18</span> <span class="content">Composition with Parallel Algorithms</span></a>
      <li>
       <a href="#design-sender-factories"><span class="secno">4.19</span> <span class="content">User-facing sender factories</span></a>
       <ol class="toc">
        <li><a href="#design-sender-factory-schedule"><span class="secno">4.19.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code></span></a>
        <li><a href="#design-sender-factory-just"><span class="secno">4.19.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just</c-></code></span></a>
        <li><a href="#design-sender-factory-transfer_just"><span class="secno">4.19.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code></span></a>
        <li><a href="#design-sender-factory-just_error"><span class="secno">4.19.4</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code></span></a>
        <li><a href="#design-sender-factory-just_done"><span class="secno">4.19.5</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code></span></a>
       </ol>
      <li>
       <a href="#design-sender-adaptors"><span class="secno">4.20</span> <span class="content">User-facing sender adaptors</span></a>
       <ol class="toc">
        <li><a href="#design-sender-adaptor-transfer"><span class="secno">4.20.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code></span></a>
        <li><a href="#design-sender-adaptor-then"><span class="secno">4.20.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code></span></a>
        <li><a href="#design-sender-adaptor-upon"><span class="secno">4.20.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_</c-><c- o>*</c-></code></span></a>
        <li><a href="#design-sender-adaptor-let"><span class="secno">4.20.4</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_</c-><c- o>*</c-></code></span></a>
        <li><a href="#design-sender-adaptor-on"><span class="secno">4.20.5</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code></span></a>
        <li><a href="#design-sender-adaptor-into_variant"><span class="secno">4.20.6</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code></span></a>
        <li><a href="#design-sender-adaptor-done_as_optional"><span class="secno">4.20.7</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code></span></a>
        <li><a href="#design-sender-adaptor-done_as_error"><span class="secno">4.20.8</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code></span></a>
        <li><a href="#design-sender-adaptor-bulk"><span class="secno">4.20.9</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code></span></a>
        <li><a href="#design-sender-adaptor-split"><span class="secno">4.20.10</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code></span></a>
        <li><a href="#design-sender-adaptor-when_all"><span class="secno">4.20.11</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code></span></a>
        <li><a href="#design-sender-adaptor-transfer_when_all"><span class="secno">4.20.12</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code></span></a>
        <li><a href="#design-sender-adaptor-ensure_started"><span class="secno">4.20.13</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code></span></a>
       </ol>
      <li>
       <a href="#design-sender-consumers"><span class="secno">4.21</span> <span class="content">User-facing sender consumers</span></a>
       <ol class="toc">
        <li><a href="#design-sender-consumer-start_detached"><span class="secno">4.21.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code></span></a>
        <li><a href="#design-sender-consumer-sync_wait"><span class="secno">4.21.2</span> <span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code></span></a>
       </ol>
      <li><a href="#design-execute"><span class="secno">4.22</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code></span></a>
     </ol>
    <li>
     <a href="#design-implementer"><span class="secno">5</span> <span class="content">Design - implementer side</span></a>
     <ol class="toc">
      <li><a href="#design-receivers"><span class="secno">5.1</span> <span class="content">Receivers serve as glue between senders</span></a>
      <li><a href="#design-states"><span class="secno">5.2</span> <span class="content">Operation states represent work</span></a>
      <li><a href="#design-connect"><span class="secno">5.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code></span></a>
      <li><a href="#design-customization"><span class="secno">5.4</span> <span class="content">Sender algorithms are customizable</span></a>
      <li><a href="#design-laziness"><span class="secno">5.5</span> <span class="content">Sender adaptors are lazy</span></a>
      <li><a href="#design-fusion"><span class="secno">5.6</span> <span class="content">Lazy senders provide optimization opportunities</span></a>
      <li><a href="#design-transition-details"><span class="secno">5.7</span> <span class="content">Execution context transitions are two-step</span></a>
      <li><a href="#design-typed"><span class="secno">5.8</span> <span class="content">Most senders are typed</span></a>
      <li><a href="#design-dispatch"><span class="secno">5.9</span> <span class="content">Ranges-style CPOs vs <code class="highlight"><c- n>tag_invoke</c-></code></span></a>
     </ol>
    <li><a href="#spec"><span class="secno">6</span> <span class="content">Specification</span></a>
    <li>
     <a href="#spec-utilities"><span class="secno">7</span> <span class="content">General utilities library <b>[utilities]</b></span></a>
     <ol class="toc">
      <li>
       <a href="#spec-function.objects"><span class="secno">7.1</span> <span class="content">Function objects <b>[function.objects]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-functional.syn"><span class="secno">7.1.1</span> <span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>functional</c-><c- o>></c-></code> synopsis <b>[functional.syn]</b></span></a>
        <li><a href="#spec-func.tag_invoke"><span class="secno">7.1.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>tag_invoke</c-></code> <b>[func.tag_invoke]</b></span></a>
       </ol>
     </ol>
    <li>
     <a href="#spec-thread"><span class="secno">8</span> <span class="content">Thread support library <b>[thread]</b></span></a>
     <ol class="toc">
      <li>
       <a href="#spec-thread.stoptoken"><span class="secno">8.1</span> <span class="content">Stop tokens <b>[thread.stoptoken]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-thread.stoptoken.syn"><span class="secno">8.1.1</span> <span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>stop_token</c-><c- o>></c-></code> synopsis <b>[thread.stoptoken.syn]</b></span></a>
        <li><a href="#spec-thread.stoptoken.concepts"><span class="secno">8.1.2</span> <span class="content">Stop token concepts <b>[thread.stoptoken.concepts]</b></span></a>
       </ol>
     </ol>
    <li>
     <a href="#spec-execution"><span class="secno">9</span> <span class="content">Execution control library <b>[execution]</b></span></a>
     <ol class="toc">
      <li><a href="#spec-execution.syn"><span class="secno">9.1</span> <span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>execution</c-><c- o>></c-></code> synopsis <b>[execution.syn]</b></span></a>
      <li><a href="#spec-execution.helpers"><span class="secno">9.2</span> <span class="content">Helper concepts <b>[execution.helpers]</b></span></a>
      <li>
       <a href="#spec-execution.schedulers"><span class="secno">9.3</span> <span class="content">Schedulers <b>[execution.schedulers] </b></span></a>
       <ol class="toc">
        <li>
         <a href="#spec-execution.schedulers.queries"><span class="secno">9.3.1</span> <span class="content">Scheduler queries <b>[execution.schedulers.queries]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.schedulers.queries.get_forward_progress_guarantee"><span class="secno">9.3.1.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-></code> <b>[execution.schedulers.queries.get_forward_progress_guarantee]</b></span></a>
          <li><a href="#spec-execution.schedulers.queries.execute_may_block_caller"><span class="secno">9.3.1.2</span> <span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code> <b>[execution.schedulers.queries.execute_may_block_caller</b></span></a>
         </ol>
       </ol>
      <li>
       <a href="#spec-execution.receivers"><span class="secno">9.4</span> <span class="content">Receivers <b>[execution.receivers]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-execution.receivers.set_value"><span class="secno">9.4.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> <b>[execution.receivers.set_value]</b></span></a>
        <li><a href="#spec-execution.receivers.set_error"><span class="secno">9.4.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> <b>[execution.receivers.set_error]</b></span></a>
        <li><a href="#spec-execution.receivers.set_done"><span class="secno">9.4.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> <b>[execution.receivers.set_done]</b></span></a>
        <li>
         <a href="#spec-execution.receivers.queries"><span class="secno">9.4.4</span> <span class="content">Receiver queries <b>[execution.receivers.queries]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.receivers.queries.get_scheduler"><span class="secno">9.4.4.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-></code> <b>[execution.receivers.queries.get_scheduler]</b></span></a>
          <li><a href="#spec-execution.receivers.queries.get_allocator"><span class="secno">9.4.4.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-></code> <b>[execution.receivers.queries.get_allocator]</b></span></a>
          <li><a href="#spec-execution.receivers.queries.get_stop_token"><span class="secno">9.4.4.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-></code> <b>[execution.receivers.queries.get_stop_token]</b></span></a>
         </ol>
       </ol>
      <li>
       <a href="#spec-execution.op_state"><span class="secno">9.5</span> <span class="content">Operation states <b>[execution.op_state]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-execution.op_state.start"><span class="secno">9.5.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> <b>[execution.op_state.start]</b></span></a>
       </ol>
      <li>
       <a href="#spec-execution.senders"><span class="secno">9.6</span> <span class="content">Senders <b>[execution.senders]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-execution.senders.traits"><span class="secno">9.6.1</span> <span class="content">Sender traits <b>[execution.senders.traits]</b></span></a>
        <li><a href="#spec-execution.senders.connect"><span class="secno">9.6.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> <b>[execution.senders.connect]</b></span></a>
        <li>
         <a href="#spec-execution.senders.queries"><span class="secno">9.6.3</span> <span class="content">Sender queries <b>[execution.senders.queries]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.senders.queries.get_completion_scheduler"><span class="secno">9.6.3.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code> <b>[execution.senders.queries.get_completion_scheduler]</b></span></a>
         </ol>
        <li>
         <a href="#spec-execution.senders.factories"><span class="secno">9.6.4</span> <span class="content">Sender factories <b>[execution.senders.factories]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.senders.factories.general"><span class="secno">9.6.4.1</span> <span class="content">General <b>[execution.senders.factories.general]</b></span></a>
          <li><a href="#spec-execution.senders.schedule"><span class="secno">9.6.4.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> <b>[execution.senders.schedule]</b></span></a>
          <li><a href="#spec-execution.senders.just"><span class="secno">9.6.4.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just</c-></code> <b>[execution.senders.just]</b></span></a>
          <li><a href="#spec-execution.senders.transfer_just"><span class="secno">9.6.4.4</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code> <b>[execution.senders.transfer_just]</b></span></a>
          <li><a href="#spec-execution.senders.just_error"><span class="secno">9.6.4.5</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code> <b>[execution.senders.just_error]</b></span></a>
          <li><a href="#spec-execution.senders.just_done"><span class="secno">9.6.4.6</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code> <b>[execution.senders.just_done]</b></span></a>
         </ol>
        <li>
         <a href="#spec-execution.senders.adaptors"><span class="secno">9.6.5</span> <span class="content">Sender adaptors <b>[execution.senders.adaptors]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.senders.adaptors.general"><span class="secno">9.6.5.1</span> <span class="content">General <b>[execution.senders.adaptors.general]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.objects"><span class="secno">9.6.5.2</span> <span class="content">Sender adaptor closure objects <b>[execution.senders.adaptor.objects]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.on"><span class="secno">9.6.5.3</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code> <b>[execution.senders.adaptors.on]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.transfer"><span class="secno">9.6.5.4</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> <b>[execution.senders.adaptors.transfer]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.schedule_from"><span class="secno">9.6.5.5</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-></code> <b>[execution.senders.adaptors.schedule_from]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.then"><span class="secno">9.6.5.6</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> <b>[execution.senders.adaptors.then]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.upon_error"><span class="secno">9.6.5.7</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-></code> <b>[execution.senders.adaptors.upon_error]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.upon_done"><span class="secno">9.6.5.8</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code> <b>[execution.senders.adaptors.upon_done]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.let_value"><span class="secno">9.6.5.9</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-></code> <b>[execution.senders.adaptors.let_value]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.let_error"><span class="secno">9.6.5.10</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-></code> <b>[execution.senders.adaptors.let_error]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.let_done"><span class="secno">9.6.5.11</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code> <b>[execution.senders.adaptors.let_done]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.bulk"><span class="secno">9.6.5.12</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code> <b>[execution.senders.adaptors.bulk]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.split"><span class="secno">9.6.5.13</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code> <b>[execution.senders.adaptors.split]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.when_all"><span class="secno">9.6.5.14</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> <b>[execution.senders.adaptors.when_all]</b></span></a>
          <li><a href="#spec-execution.senders.adaptor.transfer_when_all"><span class="secno">9.6.5.15</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> <b>[execution.senders.adaptors.transfer_when_all]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.into_variant"><span class="secno">9.6.5.16</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code> <b>[execution.senders.adaptors.into_variant]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.done_as_optional"><span class="secno">9.6.5.17</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> <b>[execution.senders.adaptors.done_as_optional]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.done_as_error"><span class="secno">9.6.5.18</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code> <b>[execution.senders.adaptors.done_as_error]</b></span></a>
          <li><a href="#spec-execution.senders.adaptors.ensure_started"><span class="secno">9.6.5.19</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> <b>[execution.senders.adaptors.ensure_started]</b></span></a>
         </ol>
        <li>
         <a href="#spec-execution.senders.consumers"><span class="secno">9.6.6</span> <span class="content">Sender consumers <b>[execution.senders.consumers]</b></span></a>
         <ol class="toc">
          <li><a href="#spec-execution.senders.consumers.start_detached"><span class="secno">9.6.6.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code> <b>[execution.senders.consumer.start_detached]</b></span></a>
          <li><a href="#spec-execution.senders.consumers.sync_wait"><span class="secno">9.6.6.2</span> <span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> <b>[execution.senders.consumers.sync_wait]</b></span></a>
         </ol>
       </ol>
      <li><a href="#spec-execution.execute"><span class="secno">9.7</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> <b>[execution.execute]</b></span></a>
      <li>
       <a href="#spec-execution.coro_utils"><span class="secno">9.8</span> <span class="content">Coroutine utilities <b>[execution.coro_utils]</b></span></a>
       <ol class="toc">
        <li><a href="#spec-execution.coro_utils.as_awaitable"><span class="secno">9.8.1</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>as_awaitable</c-></code> <b>[execution.coro_utils.as_awaitable]</b></span></a>
        <li><a href="#spec-execution.coro_utils.with_awaitable_senders"><span class="secno">9.8.2</span> <span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>with_awaitable_senders</c-></code> <b>[execution.coro_utils.with_awaitable_senders]</b></span></a>
       </ol>
     </ol>
    <li>
     <a href="#appendix-a-cancellation-examples"><span class="secno"></span> <span class="content">Appendix A - Cancellation Examples</span></a>
     <ol class="toc">
      <li><a href="#appendix-a-async_recv"><span class="secno"></span> <span class="content">Cancellation Example: Socket <code class="highlight"><c- n>async_recv</c-><c- p>()</c-></code> #</span></a>
     </ol>
    <li>
     <a href="#index"><span class="secno"></span> <span class="content">Index</span></a>
     <ol class="toc">
      <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a>
     </ol>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   <p>This paper proposes a self-contained design for a Standard C++ framework for managing asynchronous execution on generic execution contexts. It is based on the ideas in <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> and its companion papers.</p>
   <h3 class="heading settled" data-level="1.1" id="motivation"><span class="secno">1.1. </span><span class="content">Motivation</span><a class="self-link" href="#motivation"></a></h3>
   <p>Today, C++ software is increasingly asynchronous and parallel, a trend that is likely to only continue going forward.
Asynchrony and parallelism appears everywhere, from processor hardware interfaces, to networking, to file I/O, to GUIs, to accelerators.
Every C++ domain and every platform need to deal with asynchrony and parallelism, from scientific computing to video games to financial services, from the smallest mobile devices to your laptop to GPUs in the world’s fastest supercomputer.</p>
   <p>While the C++ Standard Library has a rich set concurrency primitives (<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>atomic</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>mutex</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>counting_semaphore</c-></code>, etc) and lower level building blocks (<code class="highlight"><c- n>std</c-><c- o>::</c-><c- kr>thread</c-></code>, etc), we lack a Standard vocabulary and framework for asynchrony and parallelism that C++ programmers desperately need. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>async</c-></code>/<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>future</c-></code>/<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>promise</c-></code>, C++11’s intended exposure for asynchrony, is inefficient, hard to use correctly, and severely lacking in genericity, making it unusable in many contexts.
We introduced parallel algorithms to the C++ Standard Library in C++17, and while they are an excellent start, they are all inherently synchronous and not composable.</p>
   <p>This paper proposes a Standard C++ model for asynchrony, based around three key abstractions: schedulers, senders, and receivers, and a set of customizable asynchronous algorithms.</p>
   <h3 class="heading settled" data-level="1.2" id="priorities"><span class="secno">1.2. </span><span class="content">Priorities</span><a class="self-link" href="#priorities"></a></h3>
   <ul>
    <li data-md>
     <p>Be composable and generic, allowing users to write code that can be used with many different types of execution contexts.</p>
    <li data-md>
     <p>Encapsulate common asynchronous patterns in customizable and reusable algorithms, so users don’t have to invent things themselves.</p>
    <li data-md>
     <p>Make it easy to be correct by construction.</p>
    <li data-md>
     <p>Support the diversity of execution contexts and execution agents, because not all execution agents are created equal; some are less capable than others, but not less important.</p>
    <li data-md>
     <p>Allow everything to be customized by an execution context, including transfer to other execution contexts, but don’t require that execution contexts customize everything.</p>
    <li data-md>
     <p>Care about all reasonable use cases, domains and platforms.</p>
    <li data-md>
     <p>Errors must be propagated, but error handling must not present a burden.</p>
    <li data-md>
     <p>Support cancellation, which is not an error.</p>
    <li data-md>
     <p>Have clear and concise answers for where things execute.</p>
    <li data-md>
     <p>Be able to manage and terminate the lifetimes of objects asynchronously.</p>
   </ul>
   <h3 class="heading settled" data-level="1.3" id="example-end-user"><span class="secno">1.3. </span><span class="content">Examples: End User</span><a class="self-link" href="#example-end-user"></a></h3>
   <p>In this section we demonstrate the end-user experience of asynchronous programming directly with the sender algorithms presented in this paper. See <a href="#design-sender-factories">§ 4.19 User-facing sender factories</a>, <a href="#design-sender-adaptors">§ 4.20 User-facing sender adaptors</a>, and <a href="#design-sender-consumers">§ 4.21 User-facing sender consumers</a> for short explanations of the algorithms used in these code examples.</p>
   <h4 class="heading settled" data-level="1.3.1" id="example-hello-world"><span class="secno">1.3.1. </span><span class="content">Hello world</span><a class="self-link" href="#example-hello-world"></a></h4>
<pre class="language-c++ highlight"><c- n>using</c-> <c- n>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- p>;</c->

<c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch</c-> <c- o>=</c-> <c- n>get_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->                           <c- c1>// 1</c->

<c- n>sender</c-> <c- k>auto</c-> <c- n>begin</c-> <c- o>=</c-> <c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>);</c->                                            <c- c1>// 2</c->
<c- n>sender</c-> <c- k>auto</c-> <c- n>hi_again</c-> <c- o>=</c-> <c- n>then</c-><c- p>(</c-><c- n>begin</c-><c- p>,</c-> <c- p>[]{</c->                                        <c- c1>// 3</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Hello world! Have an int."</c-><c- p>;</c->                                 <c- c1>// 3</c->
    <c- k>return</c-> <c- mi>13</c-><c- p>;</c->                                                                <c- c1>// 3</c->
<c- p>});</c->                                                                           <c- c1>// 3</c->
<c- n>sender</c-> <c- k>auto</c-> <c- n>add_42</c-> <c- o>=</c-> <c- n>then</c-><c- p>(</c-><c- n>hi_again</c-><c- p>,</c-> <c- p>[](</c-><c- b>int</c-> <c- n>arg</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>arg</c-> <c- o>+</c-> <c- mi>42</c-><c- p>;</c-> <c- p>});</c->        <c- c1>// 4</c->

<c- k>auto</c-> <c- p>[</c-><c- n>i</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>add_42</c-><c- p>).</c-><c- n>value</c-><c- p>();</c->                            <c- c1>// 5</c->
</pre>
   <p>This example demonstrates the basics of schedulers, senders, and receivers:</p>
   <ol>
    <li data-md>
     <p>First we need to get a scheduler from somewhere, such as a thread pool. A scheduler is a lightweight handle to an execution resource.</p>
    <li data-md>
     <p>To start a chain of work on a scheduler, we call <a href="#design-sender-factory-schedule">§ 4.19.1 execution::schedule</a>, which returns a sender that completes on the scheduler.  sender describes asynchronous work and sends a signal (value, error, or done) to some recipient(s) when that work completes.</p>
    <li data-md>
     <p>We use sender algorithms to produce senders and compose asynchronous work. <a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a> is a sender adaptor that takes an input sender and a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>, and calls the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> on the signal sent by the input sender. The sender returned by <code class="highlight"><c- n>then</c-></code> sends the result of that invocation. In this case, the input sender came from <code class="highlight"><c- n>schedule</c-></code>, so its <code class="highlight"><c- b>void</c-></code>, meaning it won’t send us a value, so our <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> takes no parameters. But we return an <code class="highlight"><c- b>int</c-></code>, which will be sent to the next recipient.</p>
    <li data-md>
     <p>Now, we add another operation to the chain, again using <a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a>. This time, we get sent a value - the <code class="highlight"><c- b>int</c-></code> from the previous step. We add <code class="highlight"><c- mi>42</c-></code> to it, and then return the result.</p>
    <li data-md>
     <p>Finally, we’re ready to submit the entire asynchronous pipeline and wait for its completion. Everything up until this point has been completely asynchronous; the work may not have even started yet. To ensure the work has started and then block pending its completion, we use <a href="#design-sender-consumer-sync_wait">§ 4.21.2 this_thread::sync_wait</a>, which will either return a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- p>...</c-><c- o>>></c-></code> with the value sent by the last sender, or an empty <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code> if the last sender sent a done signal, or it throws an exception if the last sender sent an error.</p>
   </ol>
   <h4 class="heading settled" data-level="1.3.2" id="example-async-inclusive-scan"><span class="secno">1.3.2. </span><span class="content">Asynchronous inclusive scan</span><a class="self-link" href="#example-async-inclusive-scan"></a></h4>
<pre class="language-c++ highlight"><c- n>using</c-> <c- n>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- p>;</c->

<c- n>sender</c-> <c- k>auto</c-> <c- n>async_inclusive_scan</c-><c- p>(</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch</c-><c- p>,</c->                          <c- c1>// 2</c->
                                 <c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- k>const</c-> <c- b>double</c-><c- o>></c-> <c- n>input</c-><c- p>,</c->               <c- c1>// 1</c->
                                 <c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- b>double</c-><c- o>></c-> <c- n>output</c-><c- p>,</c->                    <c- c1>// 1</c->
                                 <c- b>double</c-> <c- n>init</c-><c- p>,</c->                                 <c- c1>// 1</c->
                                 <c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>tile_count</c-><c- p>)</c->                      <c- c1>// 3</c->
<c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- k>const</c-> <c- n>tile_size</c-> <c- o>=</c-> <c- p>(</c-><c- n>input</c-><c- p>.</c-><c- n>size</c-><c- p>()</c-> <c- o>+</c-> <c- n>tile_count</c-> <c- o>-</c-> <c- mi>1</c-><c- p>)</c-> <c- o>/</c-> <c- n>tile_count</c-><c- p>;</c->

  <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>double</c-><c- o>></c-> <c- n>partials</c-><c- p>(</c-><c- n>tile_count</c-> <c- o>+</c-> <c- mi>1</c-><c- p>);</c->                               <c- c1>// 4</c->
  <c- n>partials</c-><c- p>[</c-><c- mi>0</c-><c- p>]</c-> <c- o>=</c-> <c- n>init</c-><c- p>;</c->                                                         <c- c1>// 4</c->

  <c- k>return</c-> <c- nf>transfer_just</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>partials</c-><c- p>))</c->                              <c- c1>// 5</c->
       <c- o>|</c-> <c- n>bulk</c-><c- p>(</c-><c- n>tile_count</c-><c- p>,</c->                                                     <c- c1>// 6</c->
           <c- p>[</c-><c- o>=</c-><c- p>](</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>i</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>double</c-><c- o>>&amp;</c-> <c- n>partials</c-><c- p>)</c-> <c- p>{</c->                <c- c1>// 7</c->
             <c- k>auto</c-> <c- n>start</c-> <c- o>=</c-> <c- n>i</c-> <c- o>*</c-> <c- n>tile_size</c-><c- p>;</c->                                      <c- c1>// 8</c->
             <c- k>auto</c-> <c- n>end</c->   <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>min</c-><c- p>(</c-><c- n>input</c-><c- p>.</c-><c- n>size</c-><c- p>(),</c-> <c- p>(</c-><c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>)</c-> <c- o>*</c-> <c- n>tile_size</c-><c- p>);</c->        <c- c1>// 8</c->
             <c- n>partials</c-><c- p>[</c-><c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>]</c-> <c- o>=</c-> <c- o>*--</c-><c- n>std</c-><c- o>::</c-><c- n>inclusive_scan</c-><c- p>(</c-><c- n>begin</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-> <c- o>+</c-> <c- n>start</c-><c- p>,</c->   <c- c1>// 9</c->
                                                      <c- n>begin</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-> <c- o>+</c-> <c- n>end</c-><c- p>,</c->     <c- c1>// 9</c->
                                                      <c- n>begin</c-><c- p>(</c-><c- n>output</c-><c- p>)</c-> <c- o>+</c-> <c- n>start</c-><c- p>);</c-> <c- c1>// 9</c->
           <c- p>})</c->                                                                 <c- c1>// 10</c->
       <c- o>|</c-> <c- n>then</c-><c- p>(</c->                                                                <c- c1>// 11</c->
           <c- p>[](</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>double</c-><c- o>>&amp;</c-> <c- n>partials</c-><c- p>)</c-> <c- p>{</c->
             <c- n>std</c-><c- o>::</c-><c- n>inclusive_scan</c-><c- p>(</c-><c- n>begin</c-><c- p>(</c-><c- n>partials</c-><c- p>),</c-> <c- n>end</c-><c- p>(</c-><c- n>partials</c-><c- p>),</c->              <c- c1>// 12</c->
                                 <c- n>begin</c-><c- p>(</c-><c- n>partials</c-><c- p>));</c->                            <c- c1>// 12</c->
             <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>partials</c-><c- p>);</c->                                      <c- c1>// 13</c->
           <c- p>})</c->
       <c- o>|</c-> <c- n>bulk</c-><c- p>(</c-><c- n>tile_count</c-><c- p>,</c->                                                     <c- c1>// 14</c->
           <c- p>[</c-><c- o>=</c-><c- p>](</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>i</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>double</c-><c- o>>&amp;</c-> <c- n>partials</c-><c- p>)</c-> <c- p>{</c->                <c- c1>// 14</c->
             <c- k>auto</c-> <c- n>start</c-> <c- o>=</c-> <c- n>i</c-> <c- o>*</c-> <c- n>tile_size</c-><c- p>;</c->                                      <c- c1>// 14</c->
             <c- k>auto</c-> <c- n>end</c->   <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>min</c-><c- p>(</c-><c- n>input</c-><c- p>.</c-><c- n>size</c-><c- p>(),</c-> <c- p>(</c-><c- n>i</c-> <c- o>+</c-> <c- mi>1</c-><c- p>)</c-> <c- o>*</c-> <c- n>tile_size</c-><c- p>);</c->        <c- c1>// 14</c->
             <c- n>std</c-><c- o>::</c-><c- n>for_each</c-><c- p>(</c-><c- n>output</c-> <c- o>+</c-> <c- n>start</c-><c- p>,</c-> <c- n>output</c-> <c- o>+</c-> <c- n>end</c-><c- p>,</c->                      <c- c1>// 14</c->
               <c- p>[</c-><c- o>&amp;</c-><c- p>]</c-> <c- p>(</c-><c- b>double</c-><c- o>&amp;</c-> <c- n>e</c-><c- p>)</c-> <c- p>{</c-> <c- n>e</c-> <c- o>=</c-> <c- n>partials</c-><c- p>[</c-><c- n>i</c-><c- p>]</c-> <c- o>+</c-> <c- n>e</c-><c- p>;</c-> <c- p>}</c->                       <c- c1>// 14</c->
             <c- p>);</c->
           <c- p>})</c->
       <c- o>|</c-> <c- n>then</c-><c- p>(</c->                                                                <c- c1>// 15</c->
           <c- p>[</c-><c- o>=</c-><c- p>](</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>double</c-><c- o>>&amp;</c-> <c- n>partials</c-><c- p>)</c-> <c- p>{</c->                               <c- c1>// 15</c->
             <c- k>return</c-> <c- n>output</c-><c- p>;</c->                                                   <c- c1>// 15</c->
           <c- p>});</c->                                                                <c- c1>// 15</c->
<c- p>}</c->
</pre>
   <p>This example builds an asynchronous computation of an inclusive scan:</p>
   <ol>
    <li data-md>
     <p>It scans a sequence of <code class="highlight"><c- b>double</c-></code>s (represented as the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- k>const</c-> <c- b>double</c-><c- o>></c-></code> <code class="highlight"><c- n>input</c-></code>) and stores the result in another sequence of <code class="highlight"><c- b>double</c-></code>s (represented as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- b>double</c-><c- o>></c-></code> <code class="highlight"><c- n>output</c-></code>).</p>
    <li data-md>
     <p>It takes a scheduler, which specifies what execution context the scan should be launched on.</p>
    <li data-md>
     <p>It also takes a <code class="highlight"><c- n>tile_count</c-></code> parameter that controls the number of execution agents that will be spawned.</p>
    <li data-md>
     <p>First we need to allocate temporary storage needed for the algorithm, which we’ll do with a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code>, <code class="highlight"><c- n>partials</c-></code>. We need one <code class="highlight"><c- b>double</c-></code> of temporary storage for each execution agent we create.</p>
    <li data-md>
     <p>Next we’ll create our initial sender with <a href="#design-sender-factory-transfer_just">§ 4.19.3 execution::transfer_just</a>. This sender will send the temporary storage, which we’ve moved into the sender. The sender has a completion scheduler of <code class="highlight"><c- n>sch</c-></code>, which means the next item in the chain will use <code class="highlight"><c- n>sch</c-></code>.</p>
    <li data-md>
     <p>Senders and sender adaptors support composition via <code class="highlight"><c- k>operator</c-><c- o>|</c-></code>, similar to C++ ranges. We’ll use <code class="highlight"><c- k>operator</c-><c- o>|</c-></code> to attach the next piece of work, which will spawn <code class="highlight"><c- n>tile_count</c-></code> execution agents using <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a> (see <a href="#design-pipeable">§ 4.12 Most sender adaptors are pipeable</a> for details).</p>
    <li data-md>
     <p>Each agent will call a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>, passing it two arguments. The first is the agent’s index (<code class="highlight"><c- n>i</c-></code>) in the <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a> operation, in this case a unique integer in <code class="highlight"><c- p>[</c-><c- mi>0</c-><c- p>,</c-> <c- n>tile_count</c-><c- p>)</c-></code>. The second argument is what the input sender sent - the temporary storage.</p>
    <li data-md>
     <p>We start by computing the start and end of the range of input and output elements that this agent is responsible for, based on our agent index.</p>
    <li data-md>
     <p>Then we do a sequential <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>inclusive_scan</c-></code> over our elements. We store the scan result for our last element, which is the sum of all of our elements, in our temporary storage <code class="highlight"><c- n>partials</c-></code>.</p>
    <li data-md>
     <p>After all computation in that initial <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a> pass has completed, every one of the spawned execution agents will have written the sum of its elements into its slot in <code class="highlight"><c- n>partials</c-></code>.</p>
    <li data-md>
     <p>Now we need to scan all of the values in <code class="highlight"><c- n>partials</c-></code>. We’ll do that with a single execution agent which will execute after the <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a> completes. We create that execution agent with <a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a>.</p>
    <li data-md>
     <p><a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a> takes an input sender and an <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> and calls the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> with the value sent by the input sender. Inside our <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>, we call <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>inclusive_scan</c-></code> on <code class="highlight"><c- n>partials</c-></code>, which the input senders will send to us.</p>
    <li data-md>
     <p>Then we return <code class="highlight"><c- n>partials</c-></code>, which the next phase will need.</p>
    <li data-md>
     <p>Finally we do another <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a> of the same shape as before. In this <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a>, we will use the scanned values in <code class="highlight"><c- n>partials</c-></code> to integrate the sums from other tiles into our elements, completing the inclusive scan.</p>
    <li data-md>
     <p><code class="highlight"><c- n>async_inclusive_scan</c-></code> returns a sender that sends the output <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- b>double</c-><c- o>></c-></code>. A consumer of the algorithm can chain additional work that uses the scan result. At the point at which <code class="highlight"><c- n>async_inclusive_scan</c-></code> returns, the computation may not have completed. In fact, it may not have even started.</p>
   </ol>
   <h4 class="heading settled" data-level="1.3.3" id="example-async-dynamically-sized-read"><span class="secno">1.3.3. </span><span class="content">Asynchronous dynamically-sized read</span><a class="self-link" href="#example-async-dynamically-sized-read"></a></h4>
<pre class="language-c++ highlight"><c- n>using</c-> <c- n>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- p>;</c->

<c- n>sender_of</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-><c- o>></c-> <c- k>auto</c-> <c- n>async_read</c-><c- p>(</c->                                       <c- c1>// 1</c->
    <c- n>sender_of</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- o>>></c-> <c- k>auto</c-> <c- n>buffer</c-><c- p>,</c->                              <c- c1>// 1</c->
    <c- k>auto</c-> <c- n>handle</c-><c- p>);</c->                                                             <c- c1>// 1</c->

<c- k>struct</c-> <c- nc>dynamic_buffer</c-> <c- p>{</c->                                                       <c- c1>// 3</c->
  <c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- p>[]</c-><c- o>></c-> <c- n>data</c-><c- p>;</c->                                          <c- c1>// 3</c->
  <c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>size</c-><c- p>;</c->                                                           <c- c1>// 3</c->
<c- p>};</c->                                                                            <c- c1>// 3</c->

<c- n>sender_of</c-><c- o>&lt;</c-><c- n>dynamic_buffer</c-><c- o>></c-> <c- k>auto</c-> <c- n>async_read_array</c-><c- p>(</c-><c- k>auto</c-> <c- n>handle</c-><c- p>)</c-> <c- p>{</c->                <c- c1>// 2</c->
  <c- k>return</c-> <c- nf>just</c-><c- p>(</c-><c- n>dynamic_buffer</c-><c- p>{})</c->                                               <c- c1>// 4</c->
       <c- o>|</c-> <c- n>let_value</c-><c- p>([]</c-> <c- p>(</c-><c- n>dynamic_buffer</c-><c- o>&amp;</c-> <c- n>buf</c-><c- p>)</c-> <c- p>{</c->                                 <c- c1>// 5</c->
           <c- k>return</c-> <c- n>just</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>as_writeable_bytes</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- p>(</c-><c- o>&amp;</c-><c- n>buf</c-><c- p>.</c-><c- n>size</c-><c- p>,</c-> <c- mi>1</c-><c- p>))</c->       <c- c1>// 6</c->
                <c- o>|</c-> <c- n>async_read</c-><c- p>(</c-><c- n>handle</c-><c- p>)</c->                                          <c- c1>// 7</c->
                <c- o>|</c-> <c- n>then</c-><c- p>(</c->                                                       <c- c1>// 8</c->
                    <c- p>[</c-><c- o>&amp;</c-><c- p>]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>bytes_read</c-><c- p>)</c-> <c- p>{</c->                            <c- c1>// 9</c->
                      <c- n>assert</c-><c- p>(</c-><c- n>bytes_read</c-> <c- o>==</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>buf</c-><c- p>.</c-><c- n>size</c-><c- p>));</c->                 <c- c1>// 10</c->
                      <c- n>buf</c-><c- p>.</c-><c- n>data</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>make_unique</c-><c- p>(</c-><c- n>new</c-> <c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- p>[</c-><c- n>buf</c-><c- p>.</c-><c- n>size</c-><c- p>]);</c->   <c- c1>// 11</c->
                      <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>span</c-><c- p>(</c-><c- n>buf</c-><c- p>.</c-><c- n>data</c-><c- p>.</c-><c- n>get</c-><c- p>(),</c-> <c- n>buf</c-><c- p>.</c-><c- n>size</c-><c- p>);</c->             <c- c1>// 12</c->
                    <c- p>}</c->
                <c- o>|</c-> <c- n>async_read</c-><c- p>(</c-><c- n>handle</c-><c- p>)</c->                                          <c- c1>// 13</c->
                <c- o>|</c-> <c- n>then</c-><c- p>(</c->
                    <c- p>[</c-><c- o>&amp;</c-><c- p>]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>bytes_read</c-><c- p>)</c-> <c- p>{</c->
                      <c- n>assert</c-><c- p>(</c-><c- n>bytes_read</c-> <c- o>==</c-> <c- n>buf</c-><c- p>.</c-><c- n>size</c-><c- p>);</c->                         <c- c1>// 14</c->
                      <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>buf</c-><c- p>);</c->                                  <c- c1>// 15</c->
                    <c- p>});</c->
       <c- p>});</c->
<c- p>}</c->
</pre>
   <p>This example demonstrates a common asynchronous I/O pattern - reading a payload of a dynamic size by first reading the size, then reading the number of bytes specified by the size:</p>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>async_read</c-></code> is a pipeable sender adaptor. It’s a customization point object, but this is what it’s call signature looks like. It takes a sender parameter which must send an input buffer in the form of a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- o>></c-></code>, and a handle to an I/O context. It will asynchronously read into the input buffer, up to the size of the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-></code>. It returns a sender which will send the number of bytes read once the read completes.</p>
    <li data-md>
     <p><code class="highlight"><c- n>async_read_array</c-></code> takes an I/O handle and reads a size from it, and then a buffer of that many bytes. It returns a sender that sends a <code class="highlight"><c- n>dynamic_buffer</c-></code> object that owns the data that was sent.</p>
    <li data-md>
     <p><code class="highlight"><c- n>dynamic_buffer</c-></code> is an aggregate struct that contains a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- p>[]</c-><c- o>></c-></code> and a size.</p>
    <li data-md>
     <p>The first thing we do inside of <code class="highlight"><c- n>async_read_array</c-></code> is create a sender that will send a new, empty <code class="highlight"><c- n>dynamic_array</c-></code> object using <a href="#design-sender-factory-just">§ 4.19.2 execution::just</a>. We can attach more work to the pipeline using <code class="highlight"><c- k>operator</c-><c- o>|</c-></code> composition (see <a href="#design-pipeable">§ 4.12 Most sender adaptors are pipeable</a> for details).</p>
    <li data-md>
     <p>We need the lifetime of this <code class="highlight"><c- n>dynamic_array</c-></code> object to last for the entire pipeline. So, we use <code class="highlight"><c- n>let_value</c-></code>, which takes an input sender and a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> that must return a sender itself (see <a href="#design-sender-adaptor-let">§ 4.20.4 execution::let_*</a> for details). <code class="highlight"><c- n>let_value</c-></code> sends the value from the input sender to the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>. Critically, the lifetime of the sent object will last until the sender returned by the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> completes.</p>
    <li data-md>
     <p>Inside of the <code class="highlight"><c- n>let_value</c-></code> <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>, we have the rest of our logic. First, we want to initiate an <code class="highlight"><c- n>async_read</c-></code> of the buffer size. To do that, we need to send a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-></code> pointing to <code class="highlight"><c- n>buf</c-><c- p>.</c-><c- n>size</c-></code>. We can do that with <a href="#design-sender-factory-just">§ 4.19.2 execution::just</a>.</p>
    <li data-md>
     <p>We chain the <code class="highlight"><c- n>async_read</c-></code> onto the <a href="#design-sender-factory-just">§ 4.19.2 execution::just</a> sender with <code class="highlight"><c- k>operator</c-><c- o>|</c-></code>.</p>
    <li data-md>
     <p>Next, we pipe a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> that will be invoked after the <code class="highlight"><c- n>async_read</c-></code> completes using <a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a>.</p>
    <li data-md>
     <p>That <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> gets sent the number of bytes read.</p>
    <li data-md>
     <p>We need to check that the number of bytes read is what we expected.</p>
    <li data-md>
     <p>Now that we have read the size of the data, we can allocate storage for it.</p>
    <li data-md>
     <p>We return a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>span</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>byte</c-><c- o>></c-></code> to the storage for the data from the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code>. This will be sent to the next recipient in the pipeline.</p>
    <li data-md>
     <p>And that recipient will be another <code class="highlight"><c- n>async_read</c-></code>, which will read the data.</p>
    <li data-md>
     <p>Once the data has been read, in another <a href="#design-sender-adaptor-then">§ 4.20.2 execution::then</a>, we confirm that we read the right number of bytes.</p>
    <li data-md>
     <p>Finally, we move out of and return our <code class="highlight"><c- n>dynamic_buffer</c-></code> object. It will get sent by the sender returned by <code class="highlight"><c- n>async_read_array</c-></code>. We can attach more things to that sender to use the data in the buffer.</p>
   </ol>
   <h4 class="heading settled" data-level="1.3.4" id="example-moar"><span class="secno">1.3.4. </span><span class="content">More end-user examples</span><a class="self-link" href="#example-moar"></a></h4>
   <h5 class="heading settled" data-level="1.3.4.1" id="example-sudoku"><span class="secno">1.3.4.1. </span><span class="content">Sudoku solver</span><a class="self-link" href="#example-sudoku"></a></h5>
   <p>This example comes from Kirk Shoop, who ported an example from TBB’s documentation to sender/receiver in his fork of the libunifex repo. It is a Sudoku solver that uses a configurable number of threads to explore the search space for solutions.</p>
   <p>The sender/receiver-based Sudoku solver can be found <a href="https://github.com/kirkshoop/libunifex/blob/sudoku/examples/sudoku.cpp">here</a>. Some things that are worth noting about Kirk’s solution:</p>
   <ol>
    <li data-md>
     <p>Although it schedules asychronous work onto a thread pool, and each unit of work will schedule more work, its use of structured concurrency patterns make reference counting unnecessary. The solution does not make use of <code class="highlight"><c- n>shared_ptr</c-></code>.</p>
    <li data-md>
     <p>In addition to eliminating the need for reference counting, the use of structured concurrency makes it easy to ensure that resources are cleaned up on all code paths. In contrast, the TBB example that inspired this one <a href="https://github.com/oneapi-src/oneTBB/issues/568">leaks memory</a>.</p>
   </ol>
   <p>For comparison, the TBB-based Sudoku solver can be found <a href="https://github.com/oneapi-src/oneTBB/blob/40a9a1060069d37d5f66912c6ee4cf165144774b/examples/task_group/sudoku/sudoku.cpp">here</a>.</p>
   <h5 class="heading settled" data-level="1.3.4.2" id="example-file-copy"><span class="secno">1.3.4.2. </span><span class="content">File copy</span><a class="self-link" href="#example-file-copy"></a></h5>
   <p>This example also comes from Kirk Shoop which uses sender/receiver to recursively copy the files a directory tree. It demonstrates how sender/receiver can be used to do IO, using a scheduler that schedules work on Linux’s io_uring.</p>
   <p>As with the Sudoku example, this example obviates the need for reference counting by employing structured concurrency. It uses iteration with an upper limit to avoid having too many open file handles.</p>
   <p>You can find the example <a href="https://github.com/kirkshoop/libunifex/blob/filecopy/examples/file_copy.cpp">here</a>.</p>
   <h5 class="heading settled" data-level="1.3.4.3" id="example-echo-server"><span class="secno">1.3.4.3. </span><span class="content">Echo server</span><a class="self-link" href="#example-echo-server"></a></h5>
   <p>Dietmar Kuehl has a hobby project that implements networking APIs on top of sender/receiver. He recently implemented an echo server as a demo. His echo server code can be found <a href="https://github.com/dietmarkuehl/kuhllib/blob/main/src/examples/echo_server.cpp">here</a>.</p>
   <p>Below, I show the part of the echo server code. This code is executed for each client that connects to the echo server. In a loop, it reads input from a socket and echos the input back to the same socket. All of this, including the loop, is implemented with generic async algorithms.</p>
<pre class="highlight"><c- n>outstanding</c-><c- p>.</c-><c- n>start</c-><c- p>(</c->
    <c- n>EX</c-><c- o>::</c-><c- n>repeat_effect_until</c-><c- p>(</c->
          <c- n>EX</c-><c- o>::</c-><c- n>let_value</c-><c- p>(</c->
              <c- n>NN</c-><c- o>::</c-><c- n>async_read_some</c-><c- p>(</c-><c- n>ptr</c-><c- o>-></c-><c- n>d_socket</c-><c- p>,</c->
                                  <c- n>context</c-><c- p>.</c-><c- n>scheduler</c-><c- p>(),</c->
                                  <c- n>NN</c-><c- o>::</c-><c- n>buffer</c-><c- p>(</c-><c- n>ptr</c-><c- o>-></c-><c- n>d_buffer</c-><c- p>))</c->
        <c- o>|</c-> <c- n>EX</c-><c- o>::</c-><c- n>then</c-><c- p>([</c-><c- n>ptr</c-><c- p>](</c-><c- o>::</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>n</c-><c- p>){</c->
            <c- o>::</c-><c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"read='"</c-> <c- o>&lt;&lt;</c-> <c- o>::</c-><c- n>std</c-><c- o>::</c-><c- n>string_view</c-><c- p>(</c-><c- n>ptr</c-><c- o>-></c-><c- n>d_buffer</c-><c- p>,</c-> <c- n>n</c-><c- p>)</c-> <c- o>&lt;&lt;</c-> <c- s>"'</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
            <c- n>ptr</c-><c- o>-></c-><c- n>d_done</c-> <c- o>=</c-> <c- n>n</c-> <c- o>==</c-> <c- mi>0</c-><c- p>;</c->
            <c- k>return</c-> <c- n>n</c-><c- p>;</c->
        <c- p>}),</c->
          <c- p>[</c-><c- o>&amp;</c-><c- n>context</c-><c- p>,</c-> <c- n>ptr</c-><c- p>](</c-><c- o>::</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>n</c-><c- p>){</c->
            <c- k>return</c-> <c- n>NN</c-><c- o>::</c-><c- n>async_write_some</c-><c- p>(</c-><c- n>ptr</c-><c- o>-></c-><c- n>d_socket</c-><c- p>,</c->
                                        <c- n>context</c-><c- p>.</c-><c- n>scheduler</c-><c- p>(),</c->
                                        <c- n>NN</c-><c- o>::</c-><c- n>buffer</c-><c- p>(</c-><c- n>ptr</c-><c- o>-></c-><c- n>d_buffer</c-><c- p>,</c-> <c- n>n</c-><c- p>));</c->
          <c- p>})</c->
        <c- o>|</c-> <c- n>EX</c-><c- o>::</c-><c- n>then</c-><c- p>([](</c-><c- k>auto</c-><c- o>&amp;&amp;</c-><c- p>...){})</c->
        <c- p>,</c-> <c- p>[</c-><c- n>owner</c-> <c- o>=</c-> <c- o>::</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>owner</c-><c- p>)]{</c-> <c- k>return</c-> <c- n>owner</c-><c- o>-></c-><c- n>d_done</c-><c- p>;</c-> <c- p>}</c->
    <c- p>)</c->
<c- p>);</c->
</pre>
   <p>In this code, <code class="highlight"><c- n>NN</c-><c- o>::</c-><c- n>async_read_some</c-></code> and <code class="highlight"><c- n>NN</c-><c- o>::</c-><c- n>async_write_some</c-></code> are asynchronous socket-based networking APIs that return senders. <code class="highlight"><c- n>EX</c-><c- o>::</c-><c- n>repeat_effect_until</c-></code>, <code class="highlight"><c- n>EX</c-><c- o>::</c-><c- n>let_value</c-></code>, and <code class="highlight"><c- n>EX</c-><c- o>::</c-><c- n>then</c-></code> and fully generic sender adaptor algorithms that accept and return senders.</p>
   <p>This is a good example of seamless composition of async IO functions with non-IO operations. And by composing the senders in this structured way, all the state for the composite operation -- the <code class="highlight"><c- n>repeat_effect_until</c-></code> expression and all its child operations -- is stored altogether in a single object.</p>
   <h3 class="heading settled" data-level="1.4" id="example-algorithm"><span class="secno">1.4. </span><span class="content">Examples: Algorithms</span><a class="self-link" href="#example-algorithm"></a></h3>
   <p>In this section we show a few simple sender/receiver-based algorithm implementations.</p>
   <h4 class="heading settled" data-level="1.4.1" id="example-then"><span class="secno">1.4.1. </span><span class="content"><code class="highlight"><c- n>then</c-></code></span><a class="self-link" href="#example-then"></a></h4>
<pre class="language-c++ highlight"><c- c1>// For emulating "deducing this"</c->
<c- n>template</c-> <c- o>&lt;</c-><c- n>class</c-> <c- n>A</c-><c- p>,</c-> <c- n>class</c-> <c- n>B</c-><c- o>></c->
  <c- n>concept</c-> <c- n>__this</c-> <c- o>=</c-> <c- n>same_as</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>A</c-><c- o>></c-><c- p>,</c-> <c- n>B</c-><c- o>></c-><c- p>;</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- p>,</c-> <c- n>class</c-> <c- n>F</c-><c- o>></c->
<c- k>struct</c-> <c- nc>_then_receiver</c-> <c- p>{</c->
  <c- n>R</c-> <c- n>r_</c-><c- p>;</c->
  <c- n>F</c-> <c- n>f_</c-><c- p>;</c->

  <c- c1>// Customize set_value by invoking the callable and passing the result to the inner receiver</c->
  <c- n>template</c-><c- o>&lt;</c-><c- n>class</c-><c- p>...</c-> <c- n>As</c-><c- o>></c->
    <c- n>requires</c-> <c- n>receiver_of</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>F</c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>>></c->
  <c- n>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- p>,</c-> <c- n>_then_receiver</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>As</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>as</c-><c- p>)</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>self</c-><c- p>.</c-><c- n>r_</c-><c- p>,</c-> <c- n>invoke</c-><c- p>((</c-><c- n>F</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>self</c-><c- p>.</c-><c- n>f_</c-><c- p>,</c-> <c- p>(</c-><c- n>As</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>as</c-><c- p>...));</c->
  <c- p>}</c->

  <c- c1>// Forward all other tag_invoke-based CPOs (copy_cvref_t from P1450):</c->
  <c- n>template</c-> <c- o>&lt;</c-><c- n>__this</c-><c- o>&lt;</c-><c- n>_then_receiver</c-><c- o>></c-> <c- n>Self</c-><c- p>,</c-> <c- n>class</c-><c- p>...</c-> <c- n>As</c-><c- p>,</c-> <c- n>invocable</c-><c- o>&lt;</c-><c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-> <c- n>Tag</c-><c- o>></c->
  <c- n>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>Tag</c-> <c- n>tag</c-><c- p>,</c-> <c- n>Self</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>As</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>as</c-><c- p>)</c->
    <c- n>noexcept</c-><c- p>(</c-><c- n>is_nothrow_invocable_v</c-><c- o>&lt;</c-><c- n>Tag</c-><c- p>,</c-> <c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-><c- p>)</c->
    <c- o>-></c-> <c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>Tag</c-><c- p>,</c-> <c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-> <c- p>{</c->
    <c- k>return</c-> <c- p>((</c-><c- n>Tag</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>tag</c-><c- p>)(((</c-><c- n>Self</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>self</c-><c- p>).</c-><c- n>r_</c-><c- p>,</c-> <c- p>(</c-><c- n>As</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>as</c-><c- p>...);</c->
  <c- p>}</c->
<c- p>};</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>sender</c-> <c- n>S</c-><c- p>,</c-> <c- n>class</c-> <c- n>F</c-><c- o>></c->
<c- k>struct</c-> <c- nc>_then_sender</c-> <c- o>:</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>sender_base</c-> <c- p>{</c->
  <c- n>S</c-> <c- n>s_</c-><c- p>;</c->
  <c- n>F</c-> <c- n>f_</c-><c- p>;</c->

  <c- n>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- n>requires</c-> <c- n>sender_to</c-><c- o>&lt;</c-><c- n>S</c-><c- p>,</c-> <c- n>_then_receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>F</c-><c- o>>></c->
  <c- n>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>experimental</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- n>_then_sender</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>R</c-> <c- n>r</c-><c- p>)</c->
    <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_result_t</c-><c- o>&lt;</c-><c- n>S</c-><c- p>,</c-> <c- n>_then_receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>F</c-><c- o>>></c-> <c- p>{</c->
      <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s_</c-><c- p>,</c-> <c- n>_then_receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>F</c-><c- o>></c-><c- p>{(</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>,</c-> <c- p>(</c-><c- n>F</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>f_</c-><c- p>});</c->
  <c- p>}</c->
<c- p>};</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>sender</c-> <c- n>S</c-><c- p>,</c-> <c- n>class</c-> <c- n>F</c-><c- o>></c->
<c- n>sender</c-> <c- k>auto</c-> <c- n>then</c-><c- p>(</c-><c- n>S</c-> <c- n>s</c-><c- p>,</c-> <c- n>F</c-> <c- n>f</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>_then_sender</c-><c- p>{{},</c-> <c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-><c- p>,</c-> <c- p>(</c-><c- n>F</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>f</c-><c- p>};</c->
<c- p>}</c->
</pre>
   <p>This code builds a <code class="highlight"><c- n>then</c-></code> algorithm that transforms the value(s) from the input sender
with a transformation function. The result of the transformation becomes the new value.
The other receiver functions (<code class="highlight"><c- n>set_error</c-></code> and <code class="highlight"><c- n>set_done</c-></code>), as well as all receiver queries,
are passed through unchanged.</p>
   <p>In detail, it does the following:</p>
   <ol>
    <li data-md>
     <p>Defines a receiver that aggregates another receiver and an invocable which:</p>
     <ul>
      <li data-md>
       <p>Defines a constrained <code class="highlight"><c- n>tag_invoke</c-></code> overload for transforming the value channel.</p>
      <li data-md>
       <p>Defines another constrained overload of <code class="highlight"><c- n>tag_invoke</c-></code> that passes all other customizations through unchanged.</p>
     </ul>
    <li data-md>
     <p>Defines a sender that aggregates another sender and the invocable, which defines a <code class="highlight"><c- n>tag_invoke</c-></code> customization for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> that wraps the incoming receiver in the receiver from (1) and passes it and the incoming sender to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, returning the result.</p>
   </ol>
   <h4 class="heading settled" data-level="1.4.2" id="example-retry"><span class="secno">1.4.2. </span><span class="content"><code class="highlight"><c- n>retry</c-></code></span><a class="self-link" href="#example-retry"></a></h4>
<pre class="language-c++ highlight"><c- c1>// _conv needed so we can emplace construct non-movable types into</c->
<c- c1>// a std::optional.</c->
<c- n>template</c-><c- o>&lt;</c-><c- n>invocable</c-> <c- n>F</c-><c- o>></c->
  <c- n>requires</c-> <c- n>std</c-><c- o>::</c-><c- n>is_nothrow_move_constructible_v</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c->
<c- k>struct</c-> <c- nc>_conv</c-> <c- p>{</c->
  <c- n>F</c-> <c- n>f_</c-><c- p>;</c->
  <c- n>explicit</c-> <c- nf>_conv</c-><c- p>(</c-><c- n>F</c-> <c- n>f</c-><c- p>)</c-> <c- nl>noexcept</c-> <c- p>:</c-> <c- n>f_</c-><c- p>((</c-><c- n>F</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>f</c-><c- p>)</c-> <c- p>{}</c->
  <c- n>operator</c-> <c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>F</c-><c- o>></c-><c- p>()</c-> <c- o>&amp;&amp;</c-> <c- p>{</c->
    <c- k>return</c-> <c- p>((</c-><c- n>F</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>f_</c-><c- p>)();</c->
  <c- p>}</c->
<c- p>};</c->

<c- c1>// pass through all customizations except set_error, which retries the operation.</c->
<c- n>template</c-><c- o>&lt;</c-><c- n>class</c-> <c- n>O</c-><c- p>,</c-> <c- n>class</c-> <c- n>R</c-><c- o>></c->
<c- k>struct</c-> <c- nc>_retry_receiver</c-> <c- p>{</c->
  <c- n>O</c-><c- o>*</c-> <c- n>o_</c-><c- p>;</c->
  <c- n>explicit</c-> <c- nf>_retry_receiver</c-><c- p>(</c-><c- n>O</c-><c- o>*</c-> <c- n>o</c-><c- p>)</c-> <c- o>:</c-> <c- n>o_</c-><c- p>(</c-><c- n>o</c-><c- p>)</c-> <c- p>{}</c->
  <c- n>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error_t</c-><c- p>,</c-> <c- n>_retry_receiver</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- k>auto</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>noexcept</c-> <c- p>{</c->
    <c- n>self</c-><c- p>.</c-><c- n>o_</c-><c- o>-></c-><c- n>_retry</c-><c- p>();</c-> <c- c1>// This causes the op to be retried</c->
  <c- p>}</c->
  <c- c1>// Forward all other tag_invoke-based CPOs (copy_cvref_t from P1450):</c->
  <c- n>template</c-> <c- o>&lt;</c-><c- n>__this</c-><c- o>&lt;</c-><c- n>_retry_receiver</c-><c- o>></c-> <c- n>Self</c-><c- p>,</c-> <c- n>class</c-><c- p>...</c-> <c- n>As</c-><c- p>,</c-> <c- n>invocable</c-><c- o>&lt;</c-><c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-> <c- n>Tag</c-><c- o>></c->
  <c- n>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>Tag</c-> <c- n>tag</c-><c- p>,</c-> <c- n>Self</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>As</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>as</c-><c- p>)</c->
    <c- n>noexcept</c-><c- p>(</c-><c- n>is_nothrow_invocable_v</c-><c- o>&lt;</c-><c- n>Tag</c-><c- p>,</c-> <c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-><c- p>)</c->
    <c- o>-></c-> <c- n>invoke_result_t</c-><c- o>&lt;</c-><c- n>Tag</c-><c- p>,</c-> <c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>As</c-><c- p>...</c-><c- o>></c-> <c- p>{</c->
    <c- k>return</c-> <c- p>((</c-><c- n>Tag</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>tag</c-><c- p>)(((</c-><c- n>copy_cvref_t</c-><c- o>&lt;</c-><c- n>Self</c-><c- p>,</c-> <c- n>R</c-><c- o>>&amp;&amp;</c-><c- p>)</c-> <c- n>self</c-><c- p>.</c-><c- n>o_</c-><c- o>-></c-><c- n>r_</c-><c- p>,</c-> <c- p>(</c-><c- n>As</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>as</c-><c- p>...);</c->
  <c- p>}</c->
<c- p>};</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>sender</c-> <c- n>S</c-><c- o>></c->
<c- k>struct</c-> <c- nc>_retry_sender</c-> <c- o>:</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>sender_base</c-> <c- p>{</c->
  <c- n>S</c-> <c- n>s_</c-><c- p>;</c->
  <c- n>explicit</c-> <c- nf>_retry_sender</c-><c- p>(</c-><c- n>S</c-> <c- n>s</c-><c- p>)</c-> <c- o>:</c-> <c- n>s_</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-><c- p>)</c-> <c- p>{}</c->

  <c- c1>// Hold the nested operation state in an optional so we can</c->
  <c- c1>// re-construct and re-start it if the operation fails.</c->
  <c- n>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
  <c- k>struct</c-> <c- nc>_op</c-> <c- p>{</c->
    <c- n>S</c-> <c- n>s_</c-><c- p>;</c->
    <c- n>R</c-> <c- n>r_</c-><c- p>;</c->
    <c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>state_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>_retry_receiver</c-><c- o>&lt;</c-><c- n>_op</c-><c- p>,</c-> <c- n>R</c-><c- o>>>></c-> <c- n>o_</c-><c- p>;</c->

    <c- n>_op</c-><c- p>(</c-><c- n>S</c-> <c- n>s</c-><c- p>,</c-> <c- n>R</c-> <c- n>r</c-><c- p>)</c-><c- o>:</c-> <c- n>s_</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-><c- n>s</c-><c- p>),</c-> <c- n>r_</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-><c- n>r</c-><c- p>),</c-> <c- n>o_</c-><c- p>{</c-><c- n>_connect</c-><c- p>()}</c-> <c- p>{}</c->
    <c- n>_op</c-><c- p>(</c-><c- n>_op</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- n>delete</c-><c- p>;</c->

    <c- k>auto</c-> <c- nf>_connect</c-><c- p>()</c-> <c- n>noexcept</c-> <c- p>{</c->
      <c- k>return</c-> <c- n>_conv</c-><c- p>{[</c-><c- n>this</c-><c- p>]</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s_</c-><c- p>,</c-> <c- n>_retry_receiver</c-><c- o>&lt;</c-><c- n>_op</c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>{</c-><c- n>this</c-><c- p>});</c->
      <c- p>}};</c->
    <c- p>}</c->
    <c- b>void</c-> <c- nf>_retry</c-><c- p>()</c-> <c- n>noexcept</c-> <c- n>try</c-> <c- p>{</c->
      <c- n>o_</c-><c- p>.</c-><c- n>emplace</c-><c- p>(</c-><c- n>_connect</c-><c- p>());</c-> <c- c1>// potentially throwing</c->
      <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- o>*</c-><c- n>o_</c-><c- p>);</c->
    <c- p>}</c-> <c- n>catch</c-><c- p>(...)</c-> <c- p>{</c->
      <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r_</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>current_exception</c-><c- p>());</c->
    <c- p>}</c->
    <c- n>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start_t</c-><c- p>,</c-> <c- n>_op</c-><c- o>&amp;</c-> <c- n>o</c-><c- p>)</c-> <c- n>noexcept</c-> <c- p>{</c->
      <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- o>*</c-><c- n>o</c-><c- p>.</c-><c- n>o_</c-><c- p>);</c->
    <c- p>}</c->
  <c- p>};</c->

  <c- n>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- n>requires</c-> <c- n>sender_to</c-><c- o>&lt;</c-><c- n>S</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>_retry_receiver</c-><c- o>&lt;</c-><c- n>_op</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>R</c-><c- o>>></c->
  <c- n>friend</c-> <c- n>_op</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- n>_retry_sender</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>R</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>_op</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>{(</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>self</c-><c- p>.</c-><c- n>s_</c-><c- p>,</c-> <c- p>(</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>};</c->
  <c- p>}</c->
<c- p>};</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>sender</c-> <c- n>S</c-><c- o>></c->
<c- n>sender</c-> <c- k>auto</c-> <c- n>retry</c-><c- p>(</c-><c- n>S</c-> <c- n>s</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- n>_retry_sender</c-><c- p>{(</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-><c- p>};</c->
<c- p>}</c->
</pre>
   <p>The <code class="highlight"><c- n>retry</c-></code> algorithm takes a multi-shot sender and causes it to repeat on error, passing
through values and done signals. Each time the input sender is restarted, a new receiver
is connected and the resulting operation state is stored in an <code class="highlight"><c- n>optional</c-></code>, which allows us
to reinitialize it multiple times.</p>
   <p>This example does the following:</p>
   <ol>
    <li data-md>
     <p>Defines a <code class="highlight"><c- n>_conv</c-></code> utility that takes advantage of C++17’s guaranteed copy elision to
emplace a non-movable type in a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code>.</p>
    <li data-md>
     <p>Defines a <code class="highlight"><c- n>_retry_receiver</c-></code> that holds a pointer back to the operation state. It passes
all customizations through unmodified to the inner receiver owned by the operation state
except for <code class="highlight"><c- n>set_error</c-></code>, which causes a <code class="highlight"><c- n>_retry</c-><c- p>()</c-></code> function to be called instead.</p>
    <li data-md>
     <p>Defines an operation state that aggregates the input sender and receiver, and declares
storage for the nested operation state in a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code>. Constructing the operation
state constructs a <code class="highlight"><c- n>_retry_receiver</c-></code> with a pointer to the (under construction) operation
state and uses it to connect to the aggregated sender.</p>
    <li data-md>
     <p>Starting the operation state dispatches to <code class="highlight"><c- n>start</c-></code> on the inner operation state.</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>_retry</c-><c- p>()</c-></code> function reinitializes the inner operation state by connecting the sender
to a new receiver, holding a pointer back to the outer operation state as before.</p>
    <li data-md>
     <p>After reinitializing the inner operation state, <code class="highlight"><c- n>_retry</c-><c- p>()</c-></code> calls <code class="highlight"><c- n>start</c-></code> on it, causing
the failed operation to be rescheduled.</p>
    <li data-md>
     <p>Defines a <code class="highlight"><c- n>_retry_sender</c-></code> that implements the <code class="highlight"><c- n>connect</c-></code> customization point to return
an operation state constructed from the passed-in sender and receiver.</p>
   </ol>
   <h3 class="heading settled" data-level="1.5" id="example-schedulers"><span class="secno">1.5. </span><span class="content">Examples: Schedulers</span><a class="self-link" href="#example-schedulers"></a></h3>
   <p>In this section we look at some schedulers of varying complexity.</p>
   <h4 class="heading settled" data-level="1.5.1" id="example-schedulers-inline"><span class="secno">1.5.1. </span><span class="content">Inline scheduler</span><a class="self-link" href="#example-schedulers-inline"></a></h4>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>inline_scheduler</c-> <c- p>{</c->
  <c- n>template</c-> <c- o>&lt;</c-><c- n>class</c-> <c- n>R</c-><c- o>></c->
    <c- k>struct</c-> <c- nc>_op</c-> <c- p>{</c->
      <c- p>[[</c-><c- n>no_unique_address</c-><c- p>]]</c-> <c- n>R</c-> <c- n>rec_</c-><c- p>;</c->
      <c- n>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start_t</c-><c- p>,</c-> <c- n>_op</c-><c- o>&amp;</c-> <c- n>op</c-><c- p>)</c-> <c- n>noexcept</c-> <c- n>try</c-> <c- p>{</c->
        <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>op</c-><c- p>.</c-><c- n>rec_</c-><c- p>);</c->
      <c- p>}</c-> <c- n>catch</c-><c- p>(...)</c-> <c- p>{</c->
        <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>op</c-><c- p>.</c-><c- n>rec_</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>current_exception</c-><c- p>());</c->
      <c- p>}</c->
    <c- p>};</c->

  <c- k>struct</c-> <c- nc>_sender</c-> <c- p>{</c->
    <c- n>template</c-> <c- o>&lt;</c-><c- n>template</c-> <c- o>&lt;</c-><c- n>class</c-><c- p>...</c-><c- o>></c-> <c- n>class</c-> <c- n>Tuple</c-><c- p>,</c->
              <c- n>template</c-> <c- o>&lt;</c-><c- n>class</c-><c- p>...</c-><c- o>></c-> <c- n>class</c-> <c- n>Variant</c-><c- o>></c->
      <c- n>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;>></c-><c- p>;</c->
    <c- n>template</c-> <c- o>&lt;</c-><c- n>template</c-> <c- o>&lt;</c-><c- n>class</c-><c- p>...</c-><c- o>></c-> <c- n>class</c-> <c- n>Variant</c-><c- o>></c->
      <c- n>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>exception_ptr</c-><c- o>></c-><c- p>;</c->
    <c- k>static</c-> <c- n>constexpr</c-> <c- b>bool</c-> <c- n>sends_done</c-> <c- o>=</c-> false<c- p>;</c->

    <c- n>template</c-> <c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>receiver_of</c-> <c- n>R</c-><c- o>></c->
      <c- n>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- n>_sender</c-><c- p>,</c-> <c- n>R</c-><c- o>&amp;&amp;</c-> <c- n>rec</c-><c- p>)</c->
        <c- n>noexcept</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_nothrow_constructible_v</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>,</c-> <c- n>R</c-><c- o>></c-><c- p>)</c->
        <c- o>-></c-> <c- n>_op</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>R</c-><c- o>>></c-> <c- p>{</c->
        <c- k>return</c-> <c- p>{(</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>rec</c-><c- p>};</c->
      <c- p>}</c->
  <c- p>};</c->

  <c- n>friend</c-> <c- n>_sender</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>schedule_t</c-><c- p>,</c-> <c- k>const</c-> <c- n>inline_scheduler</c-><c- o>&amp;</c-><c- p>)</c-> <c- n>noexcept</c-> <c- p>{</c->
    <c- k>return</c-> <c- p>{};</c->
  <c- p>}</c->

  <c- b>bool</c-> <c- n>operator</c-><c- o>==</c-><c- p>(</c-><c- k>const</c-> <c- n>inline_scheduler</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>const</c-> <c- n>noexcept</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->
</pre>
   <p>The inline scheduler is a trivial scheduler that completes immediately and synchronously on
the thread that calls <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> on the operation state produced by its sender.
In other words, <code class="highlight"><c- n>start</c-><c- p>(</c-><c- n>connect</c-><c- p>(</c-><c- n>schedule</c-><c- p>(</c-><i><c- kr>inline</c-><c- o>-</c-><c- n>scheduler</c-></i><c- p>),</c-> <c- n>receiver</c-><c- p>))</c-></code> is
just a fancy way of saying <code class="highlight"><c- n>set_value</c-><c- p>(</c-><c- n>receiver</c-><c- p>)</c-></code>, with the exception of the fact that <code class="highlight"><c- n>start</c-></code> wants to be passed an lvalue.</p>
   <p>Although not a particularly useful scheduler, it serves to illustrate the basics of
implementing one. The <code class="highlight"><c- n>inline_scheduler</c-></code>:</p>
   <ol>
    <li data-md>
     <p>Customizes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> to return an instance of the sender type <code class="highlight"><c- n>_sender</c-></code>.</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>_sender</c-></code> type models the <code class="highlight"><c- n>typed_sender</c-></code> concept and provides the metadata needed
to describe it as a sender of no values (see <code class="highlight"><c- n>value_types</c-></code>) that can send an <code class="highlight"><c- n>exception_ptr</c-></code> as an error (see <code class="highlight"><c- n>error_types</c-></code>), and that never calls <code class="highlight"><c- n>set_done</c-></code> (see <code class="highlight"><c- n>sends_done</c-></code>).</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>_sender</c-></code> type customizes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> to accept a receiver of no values.
It returns an instance of type <code class="highlight"><c- n>_op</c-></code> that holds the receiver by value.</p>
    <li data-md>
     <p>The operation state customizes <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> to call <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> on the receiver, passing any exceptions to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> as an <code class="highlight"><c- n>exception_ptr</c-></code>.</p>
   </ol>
   <h4 class="heading settled" data-level="1.5.2" id="example-single-thread"><span class="secno">1.5.2. </span><span class="content">Single thread scheduler</span><a class="self-link" href="#example-single-thread"></a></h4>
   <p>This example shows how to create a scheduler for an execution context that consists of a single
thread. It is implemented in terms of a lower-level execution context called <code class="highlight"><c- n>manual_event_loop</c-></code>.</p>
<pre class="language-c++ highlight"><c- n>class</c-> <c- n>single_thread_context</c-> <c- p>{</c->
  <c- n>manual_event_loop</c-> <c- n>loop_</c-><c- p>;</c->
  <c- n>std</c-><c- o>::</c-><c- kr>thread</c-> <c- n>thread_</c-><c- p>;</c->

<c- nl>public</c-><c- p>:</c->
  <c- n>single_thread_context</c-><c- p>()</c->
    <c- o>:</c-> <c- n>loop_</c-><c- p>()</c->
    <c- p>,</c-> <c- n>thread_</c-><c- p>([</c-><c- n>this</c-><c- p>]</c-> <c- p>{</c-> <c- n>loop_</c-><c- p>.</c-><c- n>run</c-><c- p>();</c-> <c- p>})</c->
  <c- p>{}</c->

  <c- o>~</c-><c- n>single_thread_context</c-><c- p>()</c-> <c- p>{</c->
    <c- n>loop_</c-><c- p>.</c-><c- n>finish</c-><c- p>();</c->
    <c- n>thread_</c-><c- p>.</c-><c- n>join</c-><c- p>();</c->
  <c- p>}</c->

  <c- k>auto</c-> <c- n>get_scheduler</c-><c- p>()</c-> <c- n>noexcept</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>loop_</c-><c- p>.</c-><c- n>get_scheduler</c-><c- p>();</c->
  <c- p>}</c->

  <c- n>std</c-><c- o>::</c-><c- kr>thread</c-><c- o>::</c-><c- n>id</c-> <c- n>get_thread_id</c-><c- p>()</c-> <c- k>const</c-> <c- n>noexcept</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>thread_</c-><c- p>.</c-><c- n>get_id</c-><c- p>();</c->
  <c- p>}</c->
<c- p>};</c->
</pre>
   <p>The <code class="highlight"><c- n>single_thread_context</c-></code> owns an event loop and a thread to drive it. In the destructor, it tells the event
loop to finish up what it’s doing and then joins the thread, blocking for the event loop to drain.</p>
   <p>The interesting bits are in the <code class="highlight"><c- n>manual_event_loop</c-></code> context implementation. It is slightly too long to include
here, so we only provide <a href="https://github.com/brycelelbach/wg21_p2300_std_execution/blob/main/examples/schedulers/manual_event_loop.hpp">a reference to it</a>,
but there is one noteworthy detail about its implementation. It uses space in its operation state to build an
intrusive linked list of work items. In structured concurrency patterns, the operation states of nested operations
compose statically, and in an algorithm like <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code>, the composite operation state lives on the
stack for the duration of the operation. The end result is that work can be scheduled onto this thread with zero
allocations.</p>
   <h3 class="heading settled" data-level="1.6" id="intro-is-not"><span class="secno">1.6. </span><span class="content">What this proposal is <strong>not</strong></span><a class="self-link" href="#intro-is-not"></a></h3>
   <p>This paper is not a patch on top of <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a>; we are not asking to update the existing paper, we are asking to retire it in favor of this paper, which is already self-contained; any example code within this paper can be written in Standard C++, without the need
to standardize any further facilities.</p>
   <p>This paper is not an alternative design to <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a>; rather, we have taken the design in the current executors paper, and applied targeted fixes to allow it to fulfill the promises of the sender/receiver model, as well as provide all the facilities we consider
essential when writing user code using standard execution concepts; we have also applied the guidance of removing one-way executors from the paper entirely, and instead provided an algorithm based around senders that serves the same purpose.</p>
   <h3 class="heading settled" data-level="1.7" id="intro-compare"><span class="secno">1.7. </span><span class="content">Design changes from P0443</span><a class="self-link" href="#intro-compare"></a></h3>
   <ol>
    <li data-md>
     <p>The <code class="highlight"><c- n>executor</c-></code> concept has been removed and all of its proposed functionality is now based on schedulers and senders, as per SG1 direction.</p>
    <li data-md>
     <p>Properties are not included in this paper. We see them as a possible future extension, if the committee gets more comfortable with them.</p>
    <li data-md>
     <p>Senders now advertise what scheduler, if any, their evaluation will complete on.</p>
    <li data-md>
     <p>The places of execution of user code in P0443 weren’t precisely defined, whereas they are in this paper. See <a href="#design-propagation">§ 4.5 Senders can propagate completion schedulers</a>.</p>
    <li data-md>
     <p>P0443 did not propose a suite of sender algorithms necessary for writing sender code; this paper does. See <a href="#design-sender-factories">§ 4.19 User-facing sender factories</a>, <a href="#design-sender-adaptors">§ 4.20 User-facing sender adaptors</a>, and <a href="#design-sender-consumers">§ 4.21 User-facing sender consumers</a>.</p>
    <li data-md>
     <p>P0443 did not specify the semantics of variously qualified <code class="highlight"><c- n>connect</c-></code> overloads; this paper does. See <a href="#design-shot">§ 4.7 Senders can be either multi-shot or single-shot</a>.</p>
    <li data-md>
     <p>Specific type erasure facilities are omitted, as per LEWG direction. Type erasure facilities can be built on top of this proposal, as discussed in <a href="#design-dispatch">§ 5.9 Ranges-style CPOs vs tag_invoke</a>.</p>
    <li data-md>
     <p>A specific thread pool implementation is omitted, as per LEWG direction.</p>
   </ol>
   <h3 class="heading settled" data-level="1.8" id="intro-prior-art"><span class="secno">1.8. </span><span class="content">Prior art</span><a class="self-link" href="#intro-prior-art"></a></h3>
   <p>This proposal builds upon and learns from years of prior art with asynchronous and parallel programming frameworks in C++. In this section, we discuss async abstractions that have previously been suggested as a possible basis for asynchronous algorithms and why they fall short.</p>
   <h4 class="heading settled" data-level="1.8.1" id="intro-prior-art-futures"><span class="secno">1.8.1. </span><span class="content">Futures</span><a class="self-link" href="#intro-prior-art-futures"></a></h4>
   <p>A future is a handle to work that has already been scheduled for execution. It is one end of a communication channel; the other end is a promise, used to receive the result from the concurrent operation and to communicate it to the future.</p>
   <p>Futures, as traditionally realized, require the dynamic allocation and management of a shared state, synchronization, and typically type-erasure of work and continuation. Many of these costs are inherent in the nature of "future" as a handle to work that is already scheduled for execution. These expenses rule out the future abstraction for many uses and makes it a poor choice for a basis of a generic mechanism.</p>
   <h4 class="heading settled" data-level="1.8.2" id="intro-prior-art-coroutines"><span class="secno">1.8.2. </span><span class="content">Coroutines</span><a class="self-link" href="#intro-prior-art-coroutines"></a></h4>
   <p>C++20 coroutines are frequently suggested as a basis for asynchronous algorithms. It’s fair to ask why, if we added coroutines to C++, are we suggesting the addition of a library-based abstraction for asynchrony. Certainly, coroutines come with huge syntactic and semantic advantages over the alternatives.</p>
   <p>Although coroutines are lighter weight than futures, coroutines suffer many of the same problems. Since they typically start suspended, they can avoid synchronizing the chaining of dependent work. However in many cases, coroutine frames require an unavoidable dynamic allocation and indirect function calls. This is done to hide the layout of the coroutine frame from the C++ type system, which in turn makes possible the separate compilation of coroutines and certain compiler optimizations, such as optimization of the coroutine frame size.</p>
   <p>Those advantages come at a cost, though. Because of the dynamic allocation of coroutine frames, coroutines in embedded or heterogeneous environments, which often lack support for dynamic allocation, require great attention to detail. And the allocations and indirections tend to complicate the job of the inliner, often resulting in sub-optimal codegen.</p>
   <p>The coroutine language feature mitigates these shortcomings somewhat with the HALO optimization <a data-link-type="biblio" href="#biblio-p0981r0">[P0981R0]</a>, which leverages existing compiler optimizations such as allocation elision and devirtualization to inline the coroutine, completely eliminating the runtime overhead. However, HALO requires a sophisiticated compiler, and a fair number of stars need to align for the optimization to kick in. In our experience, more often than not in real-world code today’s compilers are not able to inline the coroutine, resulting in allocations and indirections in the generated code.</p>
   <p>In a suite of generic async algorithms that are expected to be callable from hot code paths, the extra allocations and indirections are a deal-breaker. It is for these reasons that we consider coroutines a poor choise for a basis of all standard async.</p>
   <h4 class="heading settled" data-level="1.8.3" id="intro-prior-art-callbacks"><span class="secno">1.8.3. </span><span class="content">Callbacks</span><a class="self-link" href="#intro-prior-art-callbacks"></a></h4>
   <p>Callbacks are the oldest, simplest, most powerful, and most efficient mechanism for creating chains of work, but suffer problems of their own. Callbacks must propagate either errors or values. This simple requirement yields many different interface possibilities. The lack of a standard callback shape obstructs generic design.</p>
   <p>Additionally, few of these possibilities accommodate cancellation signals when the user requests upstream work to stop and clean up.</p>
   <h3 class="heading settled" data-level="1.9" id="intro-field-experience"><span class="secno">1.9. </span><span class="content">Field experience</span><a class="self-link" href="#intro-field-experience"></a></h3>
   <p>This proposal draws heavily from our field experience with <a href="https://github.com/facebookexperimental/libunifex">libunifex</a>. Libunifex has seen heavy production use at Facebook. As of October 2021, it is currently used in production within the following applications and platforms:</p>
   <ul>
    <li data-md>
     <p>Facebook Messenger on iOS, Android, Windows, and macOS</p>
    <li data-md>
     <p>Instagram on iOS and Android</p>
    <li data-md>
     <p>Facebook on iOS and Android</p>
    <li data-md>
     <p>Portal</p>
    <li data-md>
     <p>An internal Facebook product that runs on Linux</p>
   </ul>
   <p>All of these applications are making direct use of the sender/receiver abstraction as presented in this paper. One product (Instagram on iOS) is making use of the sender/coroutine integration as presented. The monthly active users of these products number in the billions.</p>
   <p>This proposal also draws heavily from our experience with <a href="https://github.com/NVIDIA/thrust">Thrust</a> and <a href="https://github.com/agency-library/agency">Agency</a>. It is also inspired by the needs of countless other C++ frameworks for asynchrony, parallelism, and concurrency, including:</p>
   <ul>
    <li data-md>
     <p><a href="https://github.com/STEllAR-GROUP/hpx">HPX</a></p>
    <li data-md>
     <p><a href="https://github.com/facebook/folly/blob/master/folly/docs/Futures.md">Folly</a></p>
    <li data-md>
     <p><a href="https://stlab.cc/libraries/concurrency/">stlab</a></p>
   </ul>
   <p>Before this proposal is approved, we will present a new implementation of this proposal written from the specification and intended as a contribution to libc++. This implementation will demonstrate the viability of the design across the use cases and execution contexts that the committee has identified as essential.</p>
   <h2 class="heading settled" data-level="2" id="revisions"><span class="secno">2. </span><span class="content">Revision history</span><a class="self-link" href="#revisions"></a></h2>
   <h3 class="heading settled" data-level="2.1" id="r2"><span class="secno">2.1. </span><span class="content">R2</span><a class="self-link" href="#r2"></a></h3>
   <p>The changes since R1 are as follows:</p>
   <ul>
    <li data-md>
     <p>Remove the eagerly executing sender algorithms.</p>
    <li data-md>
     <p>Extend the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> customization point and the <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;></c-></code> template to recognize awaitables as <code class="highlight"><c- n>typed_sender</c-></code>s.</p>
    <li data-md>
     <p>Add utilities <code class="highlight"><c- n>as_awaitable</c-><c- p>()</c-></code> and <code class="highlight"><c- n>with_awaitable_senders</c-><c- o>&lt;></c-></code> so a coroutine type can trivially make senders awaitable with a coroutine.</p>
    <li data-md>
     <p>Add a section describing the design of the sender/awaitable interactions.</p>
    <li data-md>
     <p>Add a section describing the design of the cancellation support in sender/receiver.</p>
    <li data-md>
     <p>Add a section showing examples of simple sender adaptor algorithms.</p>
    <li data-md>
     <p>Add a section showing examples of simple schedulers.</p>
    <li data-md>
     <p>Add a few more examples: a sudoku solver, a parallel recursive file copy, and an echo server.</p>
    <li data-md>
     <p>Refined the forward progress guarantees on the <code class="highlight"><c- n>bulk</c-></code> algorithm.</p>
    <li data-md>
     <p>Add a section describing how to use a range of senders to represent async sequences.</p>
    <li data-md>
     <p>Add a section showing how to use senders to represent partial success.</p>
    <li data-md>
     <p>Add sender factories <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code> and <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code>.</p>
    <li data-md>
     <p>Add sender adaptors <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> and <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code>.</p>
    <li data-md>
     <p>Document more production uses of sender/receiver at scale.</p>
    <li data-md>
     <p>Various fixes of typos and bugs.</p>
   </ul>
   <h3 class="heading settled" data-level="2.2" id="r1"><span class="secno">2.2. </span><span class="content">R1</span><a class="self-link" href="#r1"></a></h3>
   <p>The changes since R0 are as follows:</p>
   <ul>
    <li data-md>
     <p>Added a new concept, <code class="highlight"><c- n>sender_of</c-></code>.</p>
    <li data-md>
     <p>Added a new scheduler query, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code>.</p>
    <li data-md>
     <p>Added a new scheduler query, <code class="highlight"><c- n>get_forward_progress_guarantee</c-></code>.</p>
    <li data-md>
     <p>Removed the <code class="highlight"><c- n>unschedule</c-></code> adaptor.</p>
    <li data-md>
     <p>Various fixes of typos and bugs.</p>
   </ul>
   <h3 class="heading settled" data-level="2.3" id="r0"><span class="secno">2.3. </span><span class="content">R0</span><a class="self-link" href="#r0"></a></h3>
   <p>Initial revision.</p>
   <h2 class="heading settled" data-level="3" id="design-intro"><span class="secno">3. </span><span class="content">Design - introduction</span><a class="self-link" href="#design-intro"></a></h2>
   <p>The following four sections describe the entirety of the proposed design.</p>
   <ul>
    <li data-md>
     <p><a href="#design-intro">§ 3 Design - introduction</a> describes the conventions used through the rest of the design sections, as well as an example illustrating how we envision code will be written using this proposal.</p>
    <li data-md>
     <p><a href="#design-user">§ 4 Design - user side</a> describes all the functionality from the perspective we intend for users: it describes the various concepts they will interact with, and what their programming model is.</p>
    <li data-md>
     <p><a href="#design-implementer">§ 5 Design - implementer side</a> describes the machinery that allows for that programming model to function, and the information contained there is necessary for people implementing senders and sender algorithms (including the standard library ones) - but is not necessary to use senders productively.</p>
   </ul>
   <h3 class="heading settled" data-level="3.1" id="design-conventions"><span class="secno">3.1. </span><span class="content">Conventions</span><a class="self-link" href="#design-conventions"></a></h3>
   <p>The following conventions are used throughout the design section:</p>
   <ol>
    <li data-md>
     <p>The namespace proposed in this paper is the same as in <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a>: <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-></code>; however, for brevity, the <code class="highlight"><c- n>std</c-><c- o>::</c-></code> part of this name is omitted. When you see <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>foo</c-></code>, treat that as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>foo</c-></code>.</p>
    <li data-md>
     <p>Universal references and explicit calls to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>move</c-></code>/<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>forward</c-></code> are omitted in code samples and signatures for simplicity; assume universal references and perfect forwarding unless stated otherwise.</p>
    <li data-md>
     <p>None of the names proposed here are names that we are particularly attached to; consider the names to be reasonable placeholders that can freely be changed, should the committee want to do so.</p>
   </ol>
   <h3 class="heading settled" data-level="3.2" id="design-queries-and-algorithms"><span class="secno">3.2. </span><span class="content">Queries and algorithms</span><a class="self-link" href="#design-queries-and-algorithms"></a></h3>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="query">query<a class="self-link" href="#query"></a></dfn> is a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> that takes some set of objects (usually one) as parameters and returns facts about those objects without modifying them. Queries are usually customization point objects, but in some cases may be functions.</p>
   <p>An <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="algorithm">algorithm</dfn> is a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>invocable</c-></code> that takes some set of objects as parameters and causes those objects to do something. Algorithms are usually customization point objects, but in some cases may be functions.</p>
   <h2 class="heading settled" data-level="4" id="design-user"><span class="secno">4. </span><span class="content">Design - user side</span><a class="self-link" href="#design-user"></a></h2>
   <h3 class="heading settled" data-level="4.1" id="design-contexts"><span class="secno">4.1. </span><span class="content">Execution contexts describe the place of execution</span><a class="self-link" href="#design-contexts"></a></h3>
   <p>An <dfn data-dfn-type="dfn" data-noexport id="execution-context">execution context<a class="self-link" href="#execution-context"></a></dfn> is a resource that represents the <em>place</em> where execution will happen. This could be a concrete resource - like a specific thread pool object, or a GPU - or a more abstract one, like the current thread of execution. Execution contexts
don’t need to have a representation in code; they are simply a term describing certain properties of execution of a function.</p>
   <h3 class="heading settled" data-level="4.2" id="design-schedulers"><span class="secno">4.2. </span><span class="content">Schedulers represent execution contexts</span><a class="self-link" href="#design-schedulers"></a></h3>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="scheduler">scheduler<a class="self-link" href="#scheduler"></a></dfn> is a lightweight handle that represents a strategy for scheduling work onto an <em>execution context</em>. Since execution contexts don’t necessarily manifest in C++ code, it’s not possible to program
directly against their API. A scheduler is a solution to that problem: the scheduler concept is defined by a single sender algorithm, <code class="highlight"><c- n>schedule</c-></code>, which returns a sender that will complete on an execution context determined
by the scheduler. Logic that you want to run on that context can be placed in the receiver’s completion-signalling method.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch</c-> <c- o>=</c-> <c- n>get_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>);</c->
<c- c1>// snd is a sender (see below) describing the creation of a new execution resource</c->
<c- c1>// on the execution context associated with sch</c->
</pre>
   <p>Note that a particular scheduler type may provide other kinds of scheduling operations
which are supported by its associated execution context. It is not limited to scheduling
purely using the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> API.</p>
   <p>Future papers will propose additional scheduler concepts that extend <code class="highlight"><c- n>scheduler</c-></code> to add other capabilities. For example:</p>
   <ul>
    <li data-md>
     <p>A <code class="highlight"><c- n>time_scheduler</c-></code> concept that extends <code class="highlight"><c- n>scheduler</c-></code> to support time-based scheduling.
Such a concept might provide access to <code class="highlight"><c- n>schedule_after</c-><c- p>(</c-><c- n>sched</c-><c- p>,</c-> <c- n>duration</c-><c- p>)</c-></code>, <code class="highlight"><c- n>schedule_at</c-><c- p>(</c-><c- n>sched</c-><c- p>,</c-> <c- n>time_point</c-><c- p>)</c-></code> and <code class="highlight"><c- n>now</c-><c- p>(</c-><c- n>sched</c-><c- p>)</c-></code> APIs.</p>
    <li data-md>
     <p>Concepts that extend <code class="highlight"><c- n>scheduler</c-></code> to support opening, reading and writing files asynchronously.</p>
    <li data-md>
     <p>Concepts that extend <code class="highlight"><c- n>scheduler</c-></code> to support connecting, sending data and receiving data over the network asynchronously.</p>
   </ul>
   <h3 class="heading settled" data-level="4.3" id="design-senders"><span class="secno">4.3. </span><span class="content">Senders describe work</span><a class="self-link" href="#design-senders"></a></h3>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="sender">sender<a class="self-link" href="#sender"></a></dfn> is an object that describes work. Senders are similar to futures in existing asynchrony designs, but unlike futures, the work that is being done to arrive at the values they will <em>send</em> is also directly described by the sender object itself. A
sender is said to <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="send">send</dfn> some values if a receiver connected (see <a href="#design-connect">§ 5.3 execution::connect</a>) to that sender will eventually <em>receive</em> said values.</p>
   <p>The primary defining sender algorithm is <a href="#design-connect">§ 5.3 execution::connect</a>; this function, however, is not a user-facing API; it is used to facilitate communication between senders and various sender algorithms, but end user code is not expected to invoke
it directly.</p>
   <p>The way user code is expected to interact with senders is by using <a data-link-type="dfn" href="#sender-algorithms" id="ref-for-sender-algorithms">sender algorithms</a>.
This paper proposes an initial set of such sender algorithms, which are described in <a href="#design-composable">§ 4.4 Senders are composable through sender algorithms</a>, <a href="#design-sender-factories">§ 4.19 User-facing sender factories</a>, <a href="#design-sender-adaptors">§ 4.20 User-facing sender adaptors</a>, and <a href="#design-sender-consumers">§ 4.21 User-facing sender consumers</a>.
For example, here is how a user can create a new sender on a scheduler, attach a continuation to it, and then wait for execution of the continuation to complete:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch</c-> <c- o>=</c-> <c- n>get_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>cont</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- p>[]{</c->
    <c- n>std</c-><c- o>::</c-><c- n>fstream</c-> <c- n>file</c-><c- p>{</c-> <c- s>"result.txt"</c-> <c- p>};</c->
    <c- n>file</c-> <c- o>&lt;&lt;</c-> <c- n>compute_result</c-><c- p>;</c->
<c- p>});</c->

<c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>cont</c-><c- p>);</c->
<c- c1>// at this point, cont has completed execution</c->
</pre>
   <h3 class="heading settled" data-level="4.4" id="design-composable"><span class="secno">4.4. </span><span class="content">Senders are composable through sender algorithms</span><a class="self-link" href="#design-composable"></a></h3>
   <p>Asynchronous programming often departs from traditional code structure and control flow that we are familiar with.
A successful asynchronous framework must provide an intuitive story for composition of asynchronous work: expressing dependencies, passing objects, managing object lifetimes, etc.</p>
   <p>The true power and utility of senders is in their composability.
With senders, users can describe generic execution pipelines and graphs, and then run them on and across a variety of different schedulers.
Senders are composed using <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="sender-algorithms">sender algorithms</dfn>:</p>
   <ul>
    <li data-md>
     <p><a data-link-type="dfn" href="#sender-factory" id="ref-for-sender-factory">sender factories</a>, algorithms that take no senders and return a sender.</p>
    <li data-md>
     <p><a data-link-type="dfn" href="#sender-adaptor" id="ref-for-sender-adaptor">sender adaptors</a>, algorithms that take (and potentially <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>) senders and return a sender.</p>
    <li data-md>
     <p><a data-link-type="dfn" href="#sender-consumer" id="ref-for-sender-consumer">sender consumers</a>, algorithms that take (and potentially <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>) senders and do not return a sender.</p>
   </ul>
   <h3 class="heading settled" data-level="4.5" id="design-propagation"><span class="secno">4.5. </span><span class="content">Senders can propagate completion schedulers</span><a class="self-link" href="#design-propagation"></a></h3>
   <p>One of the goals of executors is to support a diverse set of execution contexts, including traditional thread pools, task and fiber frameworks (like <a href="https://github.com/STEllAR-GROUP/hpx">HPX</a>) and <a href="https://github.com/StanfordLegion/legion">Legion</a>), and GPUs and other accelerators (managed by runtimes such as CUDA or SYCL).
On many of these systems, not all execution agents are created equal and not all functions can be run on all execution agents.
Having precise control over the execution context used for any given function call being submitted is important on such systems, and the users of standard execution facilities will expect to be able to express such requirements.</p>
   <p><a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> was not always clear about the <i>place of execution</i> of any given piece of code.
Precise control was present in the two-way execution API present in earlier executor designs, but it has so far been missing from the senders design. There has been a proposal (<a data-link-type="biblio" href="#biblio-p1897r3">[P1897R3]</a>) to provide a number of sender algorithms that would enforce certain rules on the places of execution
of the work described by a sender, but we have found those sender algorithms to be insufficient for achieving the best performance on all platforms that are of interest to us. The implementation strategies that we are aware of result in one of the following situations:</p>
   <ol>
    <li data-md>
     <p>trying to submit work to one execution context (such as a CPU thread pool) from another execution context (such as a GPU or a task framework), which assumes that all execution agents are as capable as a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- kr>thread</c-></code> (which they aren’t).</p>
    <li data-md>
     <p>forcibly interleaving two adjacent execution graph nodes that are both executing on one execution context (such as a GPU) with glue code that runs on another execution context (such as a CPU), which is prohibitively expensive for some execution contexts (such as CUDA or SYCL).</p>
    <li data-md>
     <p>having to customise most or all sender algorithms to support an execution context, so that you can avoid problems described in 1. and 2, which we believe is impractical and brittle based on months of field experience attempting this in <a href="https://github.com/agency-library/agency">Agency</a>.</p>
   </ol>
   <p>None of these implementation strategies are acceptable for many classes of parallel runtimes, such as task frameworks (like <a href="https://github.com/STEllAR-GROUP/hpx">HPX</a>) or accelerator runtimes (like CUDA or SYCL).</p>
   <p>Therefore, in addition to the <code class="highlight"><c- n>on</c-></code> sender algorithm from <a data-link-type="biblio" href="#biblio-p1897r3">[P1897R3]</a>, we are proposing a way for senders to advertise what scheduler (and by extension what execution context) they will complete on.
Any given sender <b>may</b> have <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="completion-schedulers">completion schedulers</dfn> for some or all of the signals (value, error, or done) it completes with (for more detail on the completion signals, see <a href="#design-receivers">§ 5.1 Receivers serve as glue between senders</a>).
When further work is attached to that sender by invoking sender algorithms, that work will also complete on an appropriate completion scheduler.</p>
   <h4 class="heading settled" data-level="4.5.1" id="design-sender-query-get_completion_scheduler"><span class="secno">4.5.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code></span><a class="self-link" href="#design-sender-query-get_completion_scheduler"></a></h4>
   <p><code class="highlight"><c- n>get_completion_scheduler</c-></code> is a query that retrieves the <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers">completion scheduler</a> for a specific completion signal from a sender.
Calling <code class="highlight"><c- n>get_completion_scheduler</c-></code> on a sender that does not have a completion scheduler for a given signal is ill-formed.
If a sender advertises a completion scheduler for a signal in this way, that sender <b>must</b> ensure that it <a data-link-type="dfn" href="#send" id="ref-for-send">sends</a> that signal on an execution agent belonging to an execution context represented by a scheduler returned from this function.
See <a href="#design-propagation">§ 4.5 Senders can propagate completion schedulers</a> for more details.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>cpu_sched</c-> <c- o>=</c-> <c- n>new_thread_scheduler</c-><c- p>{};</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>gpu_sched</c-> <c- o>=</c-> <c- n>cuda</c-><c- o>::</c-><c- n>scheduler</c-><c- p>();</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd0</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>cpu_sched</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>completion_sch0</c-> <c- o>=</c->
  <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>snd0</c-><c- p>);</c->
<c- c1>// completion_sch0 is equivalent to cpu_sched</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd0</c-><c- p>,</c-> <c- p>[]{</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"I am running on cpu_sched!</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>completion_sch1</c-> <c- o>=</c->
  <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>snd1</c-><c- p>);</c->
<c- c1>// completion_sch1 is equivalent to cpu_sched</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>snd1</c-><c- p>,</c-> <c- n>gpu_sched</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd3</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd2</c-><c- p>,</c-> <c- p>[]{</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"I am running on gpu_sched!</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>completion_sch3</c-> <c- o>=</c->
  <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>snd3</c-><c- p>);</c->
<c- c1>// completion_sch3 is equivalent to gpu_sched</c->
</pre>
   <h3 class="heading settled" data-level="4.6" id="design-transitions"><span class="secno">4.6. </span><span class="content">Execution context transitions are explicit</span><a class="self-link" href="#design-transitions"></a></h3>
   <p><a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> does not contain any mechanisms for performing an execution context transition. The only sender algorithm that can create a sender that will move execution to a <em>specific</em> execution context is <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code>, which does not take an input sender.
That means that there’s no way to construct sender chains that traverse different execution contexts. This is necessary to fulfill the promise of senders being able to replace two-way executors, which had this capability.</p>
   <p>We propose that, for senders advertising their <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers①">completion scheduler</a>, all execution context transitions <b>must</b> be explicit; running user code anywhere but where they defined it to run <b>must</b> be considered a bug.</p>
   <p>The <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> sender adaptor performs a transition from one execution context to another:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch1</c-> <c- o>=</c-> <c- p>...;</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch2</c-> <c- o>=</c-> <c- p>...;</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch1</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd1</c-><c- p>,</c-> <c- p>[]{</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"I am running on sch1!</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>then1</c-><c- p>,</c-> <c- n>sch2</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd2</c-><c- p>,</c-> <c- p>[]{</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"I am running on sch2!</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->

<c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>then2</c-><c- p>);</c->
</pre>
   <h3 class="heading settled" data-level="4.7" id="design-shot"><span class="secno">4.7. </span><span class="content">Senders can be either multi-shot or single-shot</span><a class="self-link" href="#design-shot"></a></h3>
   <p>Some senders may only support launching their operation a single time, while others may be repeatable
and support being launched multiple times. Executing the operation may consume resources owned by the
sender.</p>
   <p>For example, a sender may contain a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-></code> that it will be transferring ownership of to the
operation-state returned by a call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> so that the operation has access to
this resource. In such a sender, calling <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> consumes the sender such that after
the call the input sender is no longer valid. Such a sender will also typically be move-only so that
it can maintain unique ownership of that resource.</p>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="single-shot-sender">single-shot sender<a class="self-link" href="#single-shot-sender"></a></dfn> can only be connected to a receiver at most once. Its implementation of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> only has overloads for an rvalue-qualified sender. Callers must pass the sender
as an rvalue to the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, indicating that the call consumes the sender.</p>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="multi-shot-sender">multi-shot sender<a class="self-link" href="#multi-shot-sender"></a></dfn> can be connected to multiple receivers and can be launched multiple
times. Multi-shot senders customise <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> to accept an lvalue reference to the
sender. Callers can indicate that they want the sender to remain valid after the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> by passing an lvalue reference to the sender to call these overloads. Multi-shot senders should also define
overloads of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> that accept rvalue-qualified senders to allow the sender to be also used in places
where only a single-shot sender is required.</p>
   <p>If the user of a sender does not require the sender to remain valid after connecting it to a
receiver then it can pass an rvalue-reference to the sender to the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>.
Such usages should be able to accept either single-shot or multi-shot senders.</p>
   <p>If the caller does wish for the sender to remain valid after the call then it can pass an lvalue-qualified sender
to the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>. Such usages will only accept multi-shot senders.</p>
   <p>Algorithms that accept senders will typically either decay-copy an input sender and store it somewhere
for later usage (for example as a data-member of the returned sender) or will immediately call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> on the input sender, such as in <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> or <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code>.</p>
   <p>Some multi-use sender algorithms may require that an input sender be copy-constructible but will only call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> on an rvalue of each copy, which still results in effectively executing the operation multiple times.
Other multi-use sender algorithms may require that the sender is move-constructible but will invoke <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> on an lvalue reference to the sender.</p>
   <p>For a sender to be usable in both multi-use scenarios, it will generally be required to be both copy-constructible and lvalue-connectable.</p>
   <h3 class="heading settled" data-level="4.8" id="design-forkable"><span class="secno">4.8. </span><span class="content">Senders are forkable</span><a class="self-link" href="#design-forkable"></a></h3>
   <p>Any non-trivial program will eventually want to fork a chain of senders into independent streams of work, regardless of whether they are single-shot or multi-shot.
For instance, an incoming event to a middleware system may be required to trigger events on more than one downstream system.
This requires that we provide well defined mechanisms for making sure that connecting a sender multiple times is possible and correct.</p>
   <p>The <code class="highlight"><c- n>split</c-></code> sender adaptor facilitates connecting to a sender multiple times, regardless of whether it is single-shot or multi-shot:</p>
<pre class="highlight"><c- k>auto</c-> <c- nf>some_algorithm</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-><c- o>&amp;&amp;</c-> <c- n>input</c-><c- p>)</c-> <c- p>{</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>multi_shot</c-> <c- o>=</c-> <c- n>split</c-><c- p>(</c-><c- n>input</c-><c- p>);</c->
    <c- c1>// "multi_shot" is guaranteed to be multi-shot,</c->
    <c- c1>// regardless of whether "input" was multi-shot or not</c->

    <c- k>return</c-> <c- n>when_all</c-><c- p>(</c->
      <c- n>then</c-><c- p>(</c-><c- n>multi_shot</c-><c- p>,</c-> <c- p>[]</c-> <c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"First continuation</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c-> <c- p>}),</c->
      <c- n>then</c-><c- p>(</c-><c- n>multi_shot</c-><c- p>,</c-> <c- p>[]</c-> <c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Second continuation</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c-> <c- p>})</c->
    <c- p>);</c->
<c- p>}</c->
</pre>
   <h3 class="heading settled" data-level="4.9" id="design-join"><span class="secno">4.9. </span><span class="content">Senders are joinable</span><a class="self-link" href="#design-join"></a></h3>
   <p>Similarly to how it’s hard to write a complex program that will eventually want to fork sender chains into independent streams, it’s also hard to write a program that does not want to eventually create join nodes, where multiple independent streams of execution are
merged into a single one in an asynchronous fashion.</p>
   <p><code class="highlight"><c- n>when_all</c-></code> is a sender adaptor that returns a sender that completes when the last of the input senders completes. It <a data-link-type="dfn" href="#send" id="ref-for-send①">sends</a> a pack of values, where the elements of said pack are the values sent by the input senders, in order. <code class="highlight"><c- n>when_all</c-></code> returns a sender that also does not have an associated scheduler.</p>
   <p><code class="highlight"><c- n>transfer_when_all</c-></code> accepts an additional scheduler argument. It returns a sender whose value <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers②">completion scheduler</a> is the scheduler provided as an argument, but otherwise behaves the same as <code class="highlight"><c- n>when_all</c-></code>. You can think of it as a composition of <code class="highlight"><c- n>transfer</c-><c- p>(</c-><c- n>when_all</c-><c- p>(</c-><c- n>inputs</c-><c- p>...),</c-> <c- n>scheduler</c-><c- p>)</c-></code>, but one that allows for better efficiency through customization.</p>
   <h3 class="heading settled" data-level="4.10" id="design-cancellation"><span class="secno">4.10. </span><span class="content">Senders support cancellation</span><a class="self-link" href="#design-cancellation"></a></h3>
   <p>Senders are often used in scenarios where the application may be concurrently executing
multiple strategies for achieving some program goal. When one of these strategies succeeds
(or fails) it may not make sense to continue pursuing the other strategies as their results
are no longer useful.</p>
   <p>For example, we may want to try to simultaneously connect to multiple network servers and use
whichever server responds first. Once the first server responds we no longer need to continue
trying to connect to the other servers.</p>
   <p>Ideally, in these scenarios, we would somehow be able to request that those other strategies
stop executing promptly so that their resources (e.g. cpu, memory, I/O bandwidth) can be
released and used for other work.</p>
   <p>While the design of senders has support for cancelling an operation before it starts
by simply destroying the sender or the operation-state returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>()</c-></code> before calling <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code>, there also needs to be a standard, generic mechanism
to ask for an already-started operation to complete early.</p>
   <p>The ability to be able to cancel in-flight operations is fundamental to supporting some kinds
of generic concurrency algorithms.</p>
   <p>For example:</p>
   <ul>
    <li data-md>
     <p>a <code class="highlight"><c- n>when_all</c-><c- p>(</c-><c- n>ops</c-><c- p>...)</c-></code> algorithm should cancel other operations as soon as one operation fails</p>
    <li data-md>
     <p>a <code class="highlight"><c- n>first_successful</c-><c- p>(</c-><c- n>ops</c-><c- p>...)</c-></code> algorithm should cancel the other operations as soon as one operation completes successfuly</p>
    <li data-md>
     <p>a generic <code class="highlight"><c- n>timeout</c-><c- p>(</c-><c- n>src</c-><c- p>,</c-> <c- n>duration</c-><c- p>)</c-></code> algorithm needs to be able to cancel the <code class="highlight"><c- n>src</c-></code> operation after the timeout duration has elapsed.</p>
    <li data-md>
     <p>a <code class="highlight"><c- n>stop_when</c-><c- p>(</c-><c- n>src</c-><c- p>,</c-> <c- n>trigger</c-><c- p>)</c-></code> algorithm should cancel <code class="highlight"><c- n>src</c-></code> if <code class="highlight"><c- n>trigger</c-></code> completes first and cancel <code class="highlight"><c- n>trigger</c-></code> if <code class="highlight"><c- n>src</c-></code> completes first</p>
   </ul>
   <p>The mechanism used for communcating cancellation-requests, or stop-requests, needs to have a uniform interface
so that generic algorithms that compose sender-based operations, such as the ones listed above, are able to
communicate these cancellation requests to senders that they don’t know anything about.</p>
   <p>The design is intended to be composable so that cancellation of higher-level operations can propagate
those cancellation requests through intermediate layers to lower-level operations that need to actually
respond to the cancellation requests.</p>
   <p>For example, we can compose the algorithms mentioned above so that child operations
are cancelled when any one of the multiple cancellation conditions occurs:</p>
<pre class="highlight"><c- n>sender</c-> <c- k>auto</c-> <c- n>composed_cancellation_example</c-><c- p>(</c-><c- k>auto</c-> <c- n>query</c-><c- p>)</c-> <c- p>{</c->
  <c- k>return</c-> <c- nf>stop_when</c-><c- p>(</c->
    <c- n>timeout</c-><c- p>(</c->
      <c- n>when_all</c-><c- p>(</c->
        <c- n>first_successful</c-><c- p>(</c->
          <c- n>query_server_a</c-><c- p>(</c-><c- n>query</c-><c- p>),</c->
          <c- n>query_server_b</c-><c- p>(</c-><c- n>query</c-><c- p>)),</c->
        <c- n>load_file</c-><c- p>(</c-><c- s>"some_file.jpg"</c-><c- p>)),</c->
      <c- mi>5</c-><c- n>s</c-><c- p>),</c->
    <c- n>cancelButton</c-><c- p>.</c-><c- n>on_click</c-><c- p>());</c->
<c- p>}</c->
</pre>
   <p>In this example, if we take the operation returned by <code class="highlight"><c- n>query_server_b</c-><c- p>(</c-><c- n>query</c-><c- p>)</c-></code>, this operation will
receive a stop-request when any of the following happens:</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>first_successful</c-></code> algorithm will send a stop-request if <code class="highlight"><c- n>query_server_a</c-><c- p>(</c-><c- n>query</c-><c- p>)</c-></code> completes successfully</p>
    <li data-md>
     <p><code class="highlight"><c- n>when_all</c-></code> algorithm will send a stop-request if the <code class="highlight"><c- n>load_file</c-><c- p>(</c-><c- s>"some_file.jpg"</c-><c- p>)</c-></code> operation completes with an error or done result.</p>
    <li data-md>
     <p><code class="highlight"><c- n>timeout</c-></code> algorithm will send a stop-request if the operation does not complete within 5 seconds.</p>
    <li data-md>
     <p><code class="highlight"><c- n>stop_when</c-></code> algorithm will send a stop-request if the user clicks on the "Cancel" button in the user-interface.</p>
    <li data-md>
     <p>The parent operation consuming the <code class="highlight"><c- n>composed_cancellation_example</c-><c- p>()</c-></code> sends a stop-request</p>
   </ul>
   <p>Note that within this code there is no explicit mention of cancellation, stop-tokens, callbacks, etc.
yet the example fully supports and responds to the various cancellation sources.</p>
   <p>The intent of the design is that the common usage of cancellation in sender/receiver-based code is
primarily through use of concurrency algorithms that manage the detailed plumbing of cancellation
for you. Much like algorithms that compose senders relieve the user from having to write their own
receiver types, algorithms that introduce concurrency and provide higher-level cancellation semantics
relieve the user from having to deal with low-level details of cancellation.</p>
   <h4 class="heading settled" data-level="4.10.1" id="design-cancellation-summary"><span class="secno">4.10.1. </span><span class="content">Cancellation design summary</span><a class="self-link" href="#design-cancellation-summary"></a></h4>
   <p>The design of cancellation described in this paper is built on top of and extends the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>stop_token</c-></code>-based
cancellation facilities added in C++20, first proposed in <a data-link-type="biblio" href="#biblio-p2175r0">[P2175R0]</a>.</p>
   <p>At a high-level, the facilities proposed by this paper for supporting cancellation include:</p>
   <ul>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>stoppable_token</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>stoppable_token_for</c-></code> concepts that generalise the interface of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>stop_token</c-></code> type to allow other types with different implementation strategies.</p>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unstoppable_token</c-></code> concept for detecting whether a <code class="highlight"><c- n>stoppable_token</c-></code> can never receive a stop-request.</p>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>in_place_stop_token</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>in_place_stop_source</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>in_place_stop_callback</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-></code> types that provide a more efficient implementation of a stop-token for use in structured concurrency situations.</p>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>never_stop_token</c-></code> for use in places where you never want to issue a stop-request</p>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>()</c-></code> CPO for querying the stop-token to use for an operation from its receiver.</p>
    <li data-md>
     <p>Add <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>stop_token_type_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> for querying the type of a stop-token returned from <code class="highlight"><c- n>get_stop_token</c-><c- p>()</c-></code></p>
   </ul>
   <p>In addition, there are requirements added to some of the algorithms to specify what their cancellation
behaviour is and what the requirements of customisations of those algorithms are with respect to
cancellation.</p>
   <p>The key component that enables generic cancellation within sender-based operations is the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>()</c-></code> CPO.
This CPO takes a single parameter, which is the receiver passed to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, and returns a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>stoppable_token</c-></code> that the operation should use to check for stop-requests for that operation.</p>
   <p>As the caller of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> typically has control over the receiver type it passes, it is able to customise
the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>()</c-></code> CPO for that receiver type to return a stop-token that it has control over and that
it can use to communicate a stop-request to the operation once it has started.</p>
   <h4 class="heading settled" data-level="4.10.2" id="design-cancellation-optional"><span class="secno">4.10.2. </span><span class="content">Support for cancellation is optional</span><a class="self-link" href="#design-cancellation-optional"></a></h4>
   <p>Support for cancellation is optional, both on part of the author of the receiver and on part of the author of the sender.</p>
   <p>If the receiver does not customise the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>()</c-></code> CPO then invoking the CPO on that receiver will
invoke the default implementation which returns <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>never_stop_token</c-></code>. This is a special <code class="highlight"><c- n>stoppable_token</c-></code> type that
is statically known to always return <code class="highlight">false</code> from the <code class="highlight"><c- n>stop_possible</c-><c- p>()</c-></code> method.</p>
   <p>Sender code that tries to use this stop-token will in general result in code that handles stop-requests being
compiled out and having little to no run-time overhead.</p>
   <p>If the sender doesn’t call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>()</c-></code>, for example because the operation does not support
cancellation, then it will simply not respond to stop-requests from the caller.</p>
   <p>Note that stop-requests are generally racy in nature as there is often a race betwen an operation completing
naturally and the stop-request being made. If the operation has already completed or past the point at which
it can be cancelled when the stop-request is sent then the stop-request may just be ignored. An application
will typically need to be able to cope with senders that might ignore a stop-request anyway.</p>
   <h4 class="heading settled" data-level="4.10.3" id="design-cancellation-racy"><span class="secno">4.10.3. </span><span class="content">Cancellation is inherently racy</span><a class="self-link" href="#design-cancellation-racy"></a></h4>
   <p>Usually, an operation will attach a stop-callback at some point inside the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> so that
a subsequent stop-request will interrupt the logic.</p>
   <p>A stop-request can be issued concurrently from another thread. This means the implementation of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> needs to be careful to ensure that, once a stop-callback has been registered, that there are no data-races between
a potentially concurrently-executing stop-callback and the rest of the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> implementation.</p>
   <p>An implementation of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> that supports cancellation will generally need to perform (at least)
two separate steps: launch the operation, subscribe a stop-callback to the receiver’s stop-token. Care needs
to be taken depending on the order in which these two steps are performed.</p>
   <p>If the stop-callback is subscribed first and then the operation is launched, care needs to be taken to ensure
that a stop-request that invokes the stop-callback on another thread after the stop-callback is registered
but before the operation finishes launching does not either result in a missed cancellation request or a
data-race. e.g. by performing an atomic write after the launch has finished executing</p>
   <p>If the operation is launched first and then the stop-callback is subscribed, care needs to be taken to ensure
that if the launched operation completes concurrently on another thread that it does not destroy the operation-state
until after the stop-callback has been registered. e.g. by having the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> implementation write to
an atomic variable once it has finished registering the stop-callback and having the concurrent completion handler
check that variable and either call the completion-signalling operation or store the result and defer calling the
receiver’s completion-signalling operation to the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> call (which is still executing).</p>
   <p>For an example of an implementation strategy for solving these data-races see the <code class="highlight"><c- n>async_recv</c-><c- p>()</c-></code> example in Appendix A.</p>
   <h4 class="heading settled" data-level="4.10.4" id="design-cancellation-status"><span class="secno">4.10.4. </span><span class="content">Cancellation design status</span><a class="self-link" href="#design-cancellation-status"></a></h4>
   <p>This paper currently includes the design for cancellation as proposed in <a data-link-type="biblio" href="#biblio-p2175r0">[P2175R0]</a> - "Composable cancellation for sender-based async operations".
P2175R0 contains more details on the background motivation and prior-art and design rationale of this design.</p>
   <p>It is important to note, however, that initial review of this design in the SG1 concurrency subgroup raised some concerns
related to runtime overhead of the design in single-threaded scenarios and these concerns are still being investigated.</p>
   <p>The design of P2175R0 has been included in this paper for now, despite its potential to change, as we believe that
support for cancellation is a fundamental requirement for an async model and is required in some form to be able to
talk about the semantics of some of the algorithms proposed in this paper.</p>
   <p>This paper will be updated in the future with any changes that arise from the investigations into P2175R0.</p>
   <h3 class="heading settled" data-level="4.11" id="design-fpg"><span class="secno">4.11. </span><span class="content">Schedulers advertise their forward progress guarantees</span><a class="self-link" href="#design-fpg"></a></h3>
   <p>To decide whether a scheduler (and its associated execution context) is sufficient for a specific task, it may be necessary to know what kind of forward progress guarantees it provides for the execution agents it creates. The C++ Standard defines the following
forward progress guarantees:</p>
   <ul>
    <li data-md>
     <p><i>concurrent</i>, which requires that a thread makes progress <i>eventually</i>;</p>
    <li data-md>
     <p><i>parallel</i>, which requires that a thread makes progress once it executes a step; and</p>
    <li data-md>
     <p><i>weakly parallel</i>, which does not require that the thread makes progress.</p>
   </ul>
   <p>This paper introduces a scheduler query function, <code class="highlight"><c- n>get_forward_progress_guarantee</c-></code>, which returns one of the enumerators of a new <code class="highlight"><c- k>enum</c-></code> type, <code class="highlight"><c- n>forward_progress_guarantee</c-></code>. Each enumerator of <code class="highlight"><c- n>forward_progress_guarantee</c-></code> corresponds to one of the aforementioned
guarantees.</p>
   <h3 class="heading settled" data-level="4.12" id="design-pipeable"><span class="secno">4.12. </span><span class="content">Most sender adaptors are pipeable</span><a class="self-link" href="#design-pipeable"></a></h3>
   <p>To facilitate an intuitive syntax for composition, most sender adaptors are <dfn data-dfn-type="dfn" data-noexport id="pipeable">pipeable<a class="self-link" href="#pipeable"></a></dfn>; they can be composed (<dfn data-dfn-type="dfn" data-noexport id="piped">piped<a class="self-link" href="#piped"></a></dfn>) together with <code class="highlight"><c- k>operator</c-><c- o>|</c-></code>.
This mechanism is similar to the <code class="highlight"><c- k>operator</c-><c- o>|</c-></code> composition that C++ range adaptors support and draws inspiration from piping in *nix shells.
Pipeable sender adaptors take a sender as their first parameter and have no other sender parameters.</p>
   <p><code class="highlight"><c- n>a</c-> <c- o>|</c-> <c- n>b</c-></code> will pass the sender <code class="highlight"><c- n>a</c-></code> as the first argument to the pipeable sender adaptor <code class="highlight"><c- n>b</c-></code>. Pipeable sender adaptors support partial application of the parameters after the first. For example, all of the following are equivalent:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- n>N</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>i</c-><c- p>,</c-> <c- k>auto</c-> <c- n>d</c-><c- p>)</c-> <c- p>{});</c->
<c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>(</c-><c- n>N</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>i</c-><c- p>,</c-> <c- k>auto</c-> <c- n>d</c-><c- p>)</c-> <c- p>{})(</c-><c- n>snd</c-><c- p>);</c->
<c- n>snd</c-> <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>(</c-><c- n>N</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- b>size_t</c-> <c- n>i</c-><c- p>,</c-> <c- k>auto</c-> <c- n>d</c-><c- p>)</c-> <c- p>{});</c->
</pre>
   <p>Piping enables you to compose together senders with a linear syntax.
Without it, you’d have to use either nested function call syntax, which would cause a syntactic inversion of the direction of control flow, or you’d have to introduce a temporary variable for each stage of the pipeline.
Consider the following example where we want to execute first on a CPU thread pool, then on a CUDA GPU, then back on the CPU thread pool:</p>
   <table>
    <tbody>
     <tr>
      <th>Syntax Style 
      <th>Example 
     <tr>
      <th>Function call <br> (nested) 
      <td>
<pre class="highlight"><c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c->
             <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c->
               <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c->
                 <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c->
                   <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c->
                     <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>get_thread_pool_scheduler</c-><c- p>())</c->
                     <c- p>[]{</c-> <c- k>return</c-> <c- mi>123</c-><c- p>;</c-> <c- p>}),</c->
                   <c- n>cuda</c-><c- o>::</c-><c- n>new_stream_scheduler</c-><c- p>()),</c->
                 <c- p>[](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- mi>123</c-> <c- o>*</c-> <c- mi>5</c-><c- p>;</c-> <c- p>}),</c->
               <c- n>get_thread_pool</c-><c- p>()),</c->
             <c- p>[](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- n>i</c-> <c- o>-</c-> <c- mi>5</c-><c- p>;</c-> <c- p>});</c->
<c- k>auto</c-> <c- p>[</c-><c- n>result</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>snd</c-><c- p>).</c-><c- n>value</c-><c- p>();</c->
<c- c1>// result == 610</c->
</pre>
     <tr>
      <th>Function call <br> (named temporaries) 
      <td>
<pre class="highlight"><c- k>auto</c-> <c- n>snd0</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>get_thread_pool_scheduler</c-><c- p>());</c->
<c- k>auto</c-> <c- n>snd1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd0</c-><c- p>,</c-> <c- p>[]{</c-> <c- k>return</c-> <c- mi>123</c-><c- p>;</c-> <c- p>});</c->
<c- k>auto</c-> <c- n>snd2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>snd1</c-><c- p>,</c-> <c- n>cuda</c-><c- o>::</c-><c- n>new_stream_scheduler</c-><c- p>());</c->
<c- k>auto</c-> <c- n>snd3</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd2</c-><c- p>,</c-> <c- p>[](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- mi>123</c-> <c- o>*</c-> <c- mi>5</c-><c- p>;</c-> <c- p>})</c->
<c- k>auto</c-> <c- n>snd4</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>snd3</c-><c- p>,</c-> <c- n>get_thread_pool</c-><c- p>())</c->
<c- k>auto</c-> <c- n>snd5</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd4</c-><c- p>,</c-> <c- p>[](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- n>i</c-> <c- o>-</c-> <c- mi>5</c-><c- p>;</c-> <c- p>});</c->
<c- k>auto</c-> <c- p>[</c-><c- n>result</c-><c- p>]</c-> <c- o>=</c-> <c- o>*</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>snd4</c-><c- p>);</c->
<c- c1>// result == 610</c->
</pre>
     <tr>
      <th>Pipe 
      <td>
<pre class="highlight"><c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>get_thread_pool_scheduler</c-><c- p>())</c->
         <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>([]{</c-> <c- k>return</c-> <c- mi>123</c-><c- p>;</c-> <c- p>})</c->
         <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>cuda</c-><c- o>::</c-><c- n>new_stream_scheduler</c-><c- p>())</c->
         <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>([](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- mi>123</c-> <c- o>*</c-> <c- mi>5</c-><c- p>;</c-> <c- p>})</c->
         <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>get_thread_pool</c-><c- p>())</c->
         <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>([](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- k>return</c-> <c- n>i</c-> <c- o>-</c-> <c- mi>5</c-><c- p>;</c-> <c- p>});</c->
<c- k>auto</c-> <c- p>[</c-><c- n>result</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>snd</c-><c- p>).</c-><c- n>value</c-><c- p>();</c->
<c- c1>// result == 610</c->
</pre>
   </table>
   <p>Certain sender adaptors are not be pipeable, because using the pipeline syntax can result in confusion of the semantics of the adaptors involved. Specifically, the following sender adaptors are not pipeable.</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> and <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-></code>: Since this sender adaptor takes a variadic pack of senders, a partially applied form would be ambiguous with a non partially applied form with an arity of one less.</p>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code>: This sender adaptor changes how the sender passed to it is executed, not what happens to its result, but allowing it in a pipeline makes it read as if it performed a function more similar to <code class="highlight"><c- n>transfer</c-></code>.</p>
   </ul>
   <p>Sender consumers could be made pipeable, but we have chosen to not do so.
However, since these are terminal nodes in a pipeline and nothing can be piped after them, we believe a pipe syntax may be confusing as well as unnecessary, as consumers cannot be chained.
We believe sender consumers read better with function call syntax.</p>
   <h3 class="heading settled" data-level="4.13" id="design-range-of-senders"><span class="secno">4.13. </span><span class="content">A range of senders represents an async sequence of data</span><a class="self-link" href="#design-range-of-senders"></a></h3>
   <p>Senders represent a single unit of asynchronous work. In many cases though, what is being modelled is a sequence of data arriving asynchronously, and you want computation to happen on demand, when each element arrives. This requires nothing more than what is in this paper and the range support in C++20. A range of senders would allow you to model such input as keystrikes, mouse movements, sensor readings, or network requests.</p>
   <p>Given some expression <code class="highlight"><i><c- n>R</c-></i></code> that is a range of senders, consider the following in a coroutine that returns an async generator type:</p>
<pre class="highlight"><c- k>for</c-> <c- p>(</c-><c- k>auto</c-> <c- nl>snd</c-> <c- p>:</c-> <i><c- n>R</c-></i><c- p>)</c-> <c- p>{</c->
  <c- k>if</c-> <c- p>(</c-><c- k>auto</c-> <c- n>opt</c-> <c- o>=</c-> <c- k>co_await</c-> <c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>snd</c-><c- p>)))</c->
    <c- k>co_yield</c-> <c- n>fn</c-><c- p>(</c-><c- o>*</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>opt</c-><c- p>));</c->
  <c- k>else</c->
    <c- k>break</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>This transforms each element of the asynchronous sequence <code class="highlight"><i><c- n>R</c-></i></code> with the function <code class="highlight"><c- n>fn</c-></code> on demand, as the data arrives. The result is a new asynchronous sequence of the transformed values.</p>
   <p>Now imagine that <code class="highlight"><i><c- n>R</c-></i></code> is the simple expression <code class="highlight"><c- n>views</c-><c- o>::</c-><c- n>iota</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-> <c- o>|</c-> <c- n>views</c-><c- o>::</c-><c- n>transform</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>)</c-></code>. This creates a lazy range of senders, each of which completes immediately with monotonically increasing integers. The above code churns through the range, generating a new infine asynchronous range of values [<code class="highlight"><c- n>fn</c-><c- p>(</c-><c- mi>0</c-><c- p>)</c-></code>, <code class="highlight"><c- n>fn</c-><c- p>(</c-><c- mi>1</c-><c- p>)</c-></code>, <code class="highlight"><c- n>fn</c-><c- p>(</c-><c- mi>2</c-><c- p>)</c-></code>, ...].</p>
   <p>Far more interesting would be if <code class="highlight"><i><c- n>R</c-></i></code> were a range of senders representing, say, user actions in a UI. The above code gives a simple way to respond to user actions on demand.</p>
   <h3 class="heading settled" data-level="4.14" id="design-partial-success"><span class="secno">4.14. </span><span class="content">Senders can represent partial success</span><a class="self-link" href="#design-partial-success"></a></h3>
   <p>Receivers have three ways they can complete: with success, failure, or cancellation. This begs the question of how they can be used to represent async operations that <em>partially</em> succeed. For example, consider an API that reads from a socket. The connection could drop after the API has filled in some of the buffer. In cases like that, it makes sense to want to report both that the connection dropped and that some data has been successfully read.</p>
   <p>Often in the case of partial success, the error condition is not fatal nor does it mean the API has failed to satisfy its post-conditions. It is merely an extra piece of information about the nature of the completion. In those cases, "partial success" is another way of saying "success". As a result, it is sensible to pass both the error code and the result (if any) through the value channel, as shown below:</p>
<pre class="highlight"><c- c1>// Capture a buffer for read_socket_async to fill in</c->
<c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- n>array</c-><c- o>&lt;</c-><c- n>byte</c-><c- p>,</c-> <c- mi>1024</c-><c- o>></c-><c- p>{})</c->
  <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>let_value</c-><c- p>([</c-><c- n>socket</c-><c- p>](</c-><c- n>array</c-><c- o>&lt;</c-><c- n>byte</c-><c- p>,</c-> <c- mi>1024</c-><c- o>>&amp;</c-> <c- n>buff</c-><c- p>)</c-> <c- p>{</c->
      <c- c1>// read_socket_async completes with two values: an error_code and</c->
      <c- c1>// a count of bytes:</c->
      <c- k>return</c-> <c- nf>read_socket_async</c-><c- p>(</c-><c- n>socket</c-><c- p>,</c-> <c- n>span</c-><c- p>{</c-><c- n>buff</c-><c- p>})</c->
          <c- c1>// For success (partial and full), specify the next action:</c->
        <c- o>|</c-> <c- n>execution</c-><c- o>::</c-><c- n>let_value</c-><c- p>([](</c-><c- n>error_code</c-> <c- n>err</c-><c- p>,</c-> <c- b>size_t</c-> <c- n>bytes_read</c-><c- p>)</c-> <c- p>{</c->
            <c- k>if</c-> <c- p>(</c-><c- n>err</c-> <c- o>!=</c-> <c- mi>0</c-><c- p>)</c-> <c- p>{</c->
              <c- c1>// OK, partial success. Decide how to deal with the partial results</c->
            <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
              <c- c1>// OK, full success here.</c->
            <c- p>}</c->
          <c- p>});</c->
    <c- p>})</c->
</pre>
   <p>In other cases, the partial success is more of a partial <em>failure</em>. That happens when the error condition indicates that in some way the function failed to satisfy its post-conditions. In those cases, sending the error through the value channel loses valuable contextual information. It’s possible that bundling the error and the incomplete results into an object and passing it through the error channel makes more sense. In that way, generic algorithms will not miss the fact that a post-condition has not been met and react inappropriately.</p>
   <p>Another possibility is for an async API to return a <em>range</em> of senders: if the API completes with full success, full error, or cancellation, the returned range contains just one sender with the result. Otherwise, if the API partially fails (doesn’t satisfy its post-conditions, but some incomplete result is available), the returned range would have <em>two</em> senders: the first containing the partial result, and the second containing the error. Such an API might be used in a coroutine as follows:</p>
<pre class="highlight"><c- c1>// Declare a buffer for read_socket_async to fill in</c->
<c- n>array</c-><c- o>&lt;</c-><c- n>byte</c-><c- p>,</c-> <c- mi>1024</c-><c- o>></c-> <c- n>buff</c-><c- p>;</c->

<c- k>for</c-> <c- p>(</c-><c- k>auto</c-> <c- nl>snd</c-> <c- p>:</c-> <c- n>read_socket_async</c-><c- p>(</c-><c- n>socket</c-><c- p>,</c-> <c- n>span</c-><c- p>{</c-><c- n>buff</c-><c- p>}))</c-> <c- p>{</c->
  <c- k>try</c-> <c- p>{</c->
    <c- k>if</c-> <c- p>(</c-><c- n>optional</c-><c- o>&lt;</c-><c- b>size_t</c-><c- o>></c-> <c- n>bytes_read</c-> <c- o>=</c->
          <c- k>co_await</c-> <c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>snd</c-><c- p>)))</c->
      <c- c1>// OK, we read some bytes into buff. Process them here....</c->
    <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
      <c- c1>// The socket read was cancelled and returned no data. React</c->
      <c- c1>// appropriately.</c->
    <c- p>}</c->
  <c- p>}</c-> <c- k>catch</c-> <c- p>(...)</c-> <c- p>{</c->
    <c- c1>// read_socket_async failed to meet its post-conditions.</c->
    <c- c1>// Do some cleanup and propagate the error...</c->
  <c- p>}</c->
<c- p>}</c->
</pre>
   <p>Finally, it’s possible to combine these two approaches when the API can both partially succeed (meeting its post-conditions) and partially fail (not meeting its post-conditions).</p>
   <h3 class="heading settled" data-level="4.15" id="design-awaitables-are-senders"><span class="secno">4.15. </span><span class="content">All awaitables are senders</span><a class="self-link" href="#design-awaitables-are-senders"></a></h3>
   <p>Since C++20 added coroutines to the standard, we expect that coroutines and awaitables will be how a great many will choose to express their asynchronous code. However, in this paper, we are proposing to add a suite of asynchronous algorithms that accept senders, not awaitables. One might wonder whether and how these algorithms will be accessible to those who choose coroutines instead of senders.</p>
   <p>In truth there will be no problem because all generally awaitable types automatically model the <code class="highlight"><c- n>typed_sender</c-></code> concept. The adaptation is transparent and happens in the sender customization points, which are aware of awaitables. (By "generally awaitable" we mean types that don’t require custom <code class="highlight"><c- n>await_transform</c-></code> trickery from a promise type to make them awaitable.)</p>
   <p>For an example, imagine a coroutine type called <code class="highlight"><c- n>task</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> that knows nothing about senders. It doesn’t implement any of the sender customization points. Despite that fact, and despite the fact that the <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> algorithm is constrained with the <code class="highlight"><c- n>typed_sender</c-></code> concept, the following would compile and do what the user wants:</p>
<pre class="language-c++ highlight"><c- n>task</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>doSomeAsyncWork</c-><c- p>();</c->

<c- b>int</c-> <c- nf>main</c-><c- p>()</c-> <c- p>{</c->
  <c- c1>// OK, awaitable types satisfy the requirements for typed senders:</c->
  <c- k>auto</c-> <c- n>o</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>doSomeAsyncWork</c-><c- p>());</c->
<c- p>}</c->
</pre>
   <p>Since awaitables are senders, writing a sender-based asynchronous algorithm is trivial if you have a coroutine task type: implement the algorithm as a coroutine. If you are not bothered by the possibility of allocations and indirections as a result of using coroutines, then there is no need to ever write a sender, a receiver, or an operation state.</p>
   <h3 class="heading settled" data-level="4.16" id="design-senders-are-awaitable"><span class="secno">4.16. </span><span class="content">Many senders can be trivially made awaitable</span><a class="self-link" href="#design-senders-are-awaitable"></a></h3>
   <p>If you choose to implement your sender-based algorithms as coroutines, you’ll run into the issue of how to retrieve results from a passed-in sender. This is not a problem. If the coroutine type opts in to sender support -- trivial with the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>with_awaitable_senders</c-></code> utility -- then a large class of senders are transparently awaitable from within the coroutine.</p>
   <p>For example, consider the following trivial implementation of the sender-based <code class="highlight"><c- n>retry</c-></code> algorithm:</p>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>requires</c-> <i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>&amp;></c-> <c- c1>// See </c-><a href="#spec-execution.coro_utils.as_awaitable"><c- c1>[execution.coro_utils.as_awaitable]</c-></a>
<c- n>task</c-><c- o>&lt;</c-><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-> <c- n>retry</c-><c- p>(</c-><c- n>S</c-> <c- n>s</c-><c- p>)</c-> <c- p>{</c->
  <c- k>for</c-> <c- p>(;;)</c-> <c- p>{</c->
    <c- k>try</c-> <c- p>{</c->
      <c- k>co_return</c-> <c- k>co_await</c-> <c- n>s</c-><c- p>;</c->
    <c- p>}</c-> <c- k>catch</c-><c- p>(...)</c-> <c- p>{</c->
    <c- p>}</c->
  <c- p>}</c->
<c- p>}</c->
</pre>
   <p>Only <em>some</em> senders can be made awaitable directly because of the fact that callbacks are more expressive than coroutines. An awaitable expression has a single type: the result value of the async operation. In contrast, a callback can accept multiple arguments as the result of an operation. What’s more, the callback can have overloaded function call signatures that take different sets of arguments. There is no way to automatically map such senders into awaitables. The <code class="highlight"><c- n>with_awaitable_senders</c-></code> utility recognizes as awaitables those senders that send a single value of a single type. To await another kind of sender, a user would have to first map its value channel into a single value of a single type -- say, with the <code class="highlight"><c- n>into_variant</c-></code> sender algorithm -- before <code class="highlight"><c- k>co_await</c-></code>-ing that sender.</p>
   <h3 class="heading settled" data-level="4.17" id="design-native-coro-unwind"><span class="secno">4.17. </span><span class="content">Cancellation of a sender can unwind a stack of coroutines</span><a class="self-link" href="#design-native-coro-unwind"></a></h3>
   <p>When looking at the sender-based <code class="highlight"><c- n>retry</c-></code> algorithm in the previous section, we can see that the value and error cases are correctly handled. But what about cancellation? What happens to a coroutine that is suspended awaiting a sender that completes by calling <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code>?</p>
   <p>When your task type’s promise inherits from <code class="highlight"><c- n>with_awaitable_senders</c-></code>, what happens is this: the coroutine behaves as if an <em>uncatchable exception</em> had been thrown from the <code class="highlight"><c- k>co_await</c-></code> expression. (It is not really an exception, but it’s helpful to think of it that way.) Provided that the promise types of the calling coroutines also inherit from <code class="highlight"><c- n>with_awaitable_senders</c-></code>, or more generally implement a member function called <code class="highlight"><c- n>unhandled_done</c-></code>, the exception unwinds the chain of coroutines as if an exception were thrown except that it bypasses <code class="highlight"><c- k>catch</c-><c- p>(...)</c-></code> clauses.</p>
   <p>In order to "catch" this uncatchable done exception, one of the calling coroutines in the stack would have to await a sender that maps the done channel into either a value or an error. That is achievable with the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code>, or <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code> sender adaptors. For instance, we can use <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> to "catch" the done signal and map it into an empty optional as shown below:</p>
<pre class="language-c++ highlight"><c- k>if</c-> <c- p>(</c-><c- k>auto</c-> <c- n>opt</c-> <c- o>=</c-> <c- n>co_await</c-> <c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-><c- p>(</c-><c- n>some_sender</c-><c- p>))</c-> <c- p>{</c->
  <c- c1>// OK, some_sender completed successfully, and opt contains the result.</c->
<c- p>}</c-> <c- k>else</c-> <c- p>{</c->
  <c- c1>// some_sender completed with a cancellation signal.</c->
<c- p>}</c->
</pre>
   <p>As described in the section <a href="#design-awaitables-are-senders">"All awaitables are senders"</a>, the sender customization points recognize awaitables and adapt them transparently to model the sender concept. When <code class="highlight"><c- n>connect</c-></code>-ing an awaitable and a receiver, the adaptation layer awaits the awaitable within a coroutine that implements <code class="highlight"><c- n>unhandled_done</c-></code> in its promise type. The effect of this is that an "uncatchable" done exception propagates seamlessly out of awaitables, causing <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> to be called on the receiver.</p>
   <p>Obviously, <code class="highlight"><c- n>unhandled_done</c-></code> is a library extension of the coroutine promise interface. Many promise types will not implement <code class="highlight"><c- n>unhandled_done</c-></code>. When an uncatchable done exception tries to propagate through such a coroutine, it is treated as an unhandled exception and <code class="highlight"><c- n>terminate</c-></code> is called. The solution, as described above, is to use a sender adaptor to handle the done exception before awaiting it. It goes without saying that any future Standard Library coroutine types ought to implement <code class="highlight"><c- n>unhandled_done</c-></code>. The author of <a data-link-type="biblio" href="#biblio-p1056r1">[P1056R1]</a>, which proposes a standard coroutine task type, is in agreement.</p>
   <h3 class="heading settled" data-level="4.18" id="design-parallel-algorithms"><span class="secno">4.18. </span><span class="content">Composition with Parallel Algorithms</span><a class="self-link" href="#design-parallel-algorithms"></a></h3>
   <p>The C++ Standard Library provides a large number of algorithms that offer the potential for non-sequential execution via the use of execution policies. The set of algorithms with execution policy overloads are often referred to as "parallel algorithms", although
additional policies are available.</p>
   <p>Existing policies, such as <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>par</c-></code>, give the implementation permission to execute the algorithm in parallel. However, the choice of execution resources used to perform the work is left to the implementation.</p>
   <p>We will propose a customization point for combining schedulers with policies in order to provide control over where work will execute.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>ExecutionPolicy</c-><c- o>></c->
<i><c- n>implementation</c-><c- o>-</c-><c- n>defined</c-></i> <c- n>executing_on</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>scheduler</c-><c- p>,</c->
    <c- n>ExecutionPolicy</c-> <c- o>&amp;&amp;</c-> <c- n>policy</c->
<c- p>);</c->
</pre>
   <p>This function would return an object of an implementation-defined type which can be used in place of an execution policy as the first argument to one of the parallel algorithms. The overload selected by that object should execute its computation as requested by <code class="highlight"><c- n>policy</c-></code> while using <code class="highlight"><c- n>scheduler</c-></code> to create any work to be run. The expression may be ill-formed if <code class="highlight"><c- n>scheduler</c-></code> is not able to support the given policy.</p>
   <p>The existing parallel algorithms are synchronous; all of the effects performed by the computation are complete before the algorithm returns to its caller. This remains unchanged with the <code class="highlight"><c- n>executing_on</c-></code> customization point.</p>
   <p>In the future, we expect additional papers will propose asynchronous forms of the parallel algorithms which (1) return senders rather than values or <code class="highlight"><c- b>void</c-></code> and (2) where a customization point pairing a sender with an execution policy would similarly be used to
obtain an object of implementation-defined type to be provided as the first argument to the algorithm.</p>
   <h3 class="heading settled" data-level="4.19" id="design-sender-factories"><span class="secno">4.19. </span><span class="content">User-facing sender factories</span><a class="self-link" href="#design-sender-factories"></a></h3>
   <p>A <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="sender-factory">sender factory</dfn> is an <a data-link-type="dfn" href="#algorithm" id="ref-for-algorithm">algorithm</a> that takes no senders as parameters and returns a sender.</p>
   <h4 class="heading settled" data-level="4.19.1" id="design-sender-factory-schedule"><span class="secno">4.19.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code></span><a class="self-link" href="#design-sender-factory-schedule"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>schedule</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>scheduler</c->
<c- p>);</c->
</pre>
   <p>Returns a sender describing the start of a task graph on the provided scheduler. See <a href="#design-schedulers">§ 4.2 Schedulers represent execution contexts</a>.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sch1</c-> <c- o>=</c-> <c- n>get_system_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch1</c-><c- p>);</c->
<c- c1>// snd1 describes the creation of a new task on the system thread pool</c->
</pre>
   <h4 class="heading settled" data-level="4.19.2" id="design-sender-factory-just"><span class="secno">4.19.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just</c-></code></span><a class="self-link" href="#design-sender-factory-just"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>just</c-><c- p>(</c->
    <c- k>auto</c-> <c- p>...</c-><c- o>&amp;&amp;</c-> <c- n>values</c->
<c- p>);</c->
</pre>
   <p>Returns a sender with no <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers③">completion schedulers</a>, which <a data-link-type="dfn" href="#send" id="ref-for-send②">sends</a> the provided values. If a provided value is an lvalue reference, a copy is made inside the returned sender and a non-const lvalue reference to the copy is sent. If the provided value is an rvalue reference, it is moved into the returned sender and an rvalue reference to it is sent.</p>
<pre class="language-c++ highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- mf>3.14</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then1</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd1</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- b>double</c-> <c- n>d</c-><c- p>)</c-> <c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- n>d</c-> <c- o>&lt;&lt;</c-> <c- s>"</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- mf>3.14</c-><c- p>,</c-> <c- mi>42</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then2</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd1</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- b>double</c-> <c- n>d</c-><c- p>,</c-> <c- b>int</c-> <c- n>i</c-><c- p>)</c-> <c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- n>d</c-> <c- o>&lt;&lt;</c-> <c- s>", "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- s>"</c-><c- se>\n</c-><c- s>"</c-><c- p>;</c->
<c- p>});</c->

<c- n>std</c-><c- o>::</c-><c- n>vector</c-> <c- n>v3</c-><c- p>{</c-><c- mi>1</c-><c- p>,</c-> <c- mi>2</c-><c- p>,</c-> <c- mi>3</c-><c- p>,</c-> <c- mi>4</c-><c- p>,</c-> <c- mi>5</c-><c- p>};</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd3</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- n>v3</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then3</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd3</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>&amp;</c-> <c- n>v3copy</c-><c- p>)</c-> <c- p>{</c->
  <c- k>for</c-> <c- p>(</c-><c- k>auto</c-><c- o>&amp;&amp;</c-> <c- nl>e</c-> <c- p>:</c-> <c- n>v3copy</c-><c- p>)</c-> <c- p>{</c-> <c- n>e</c-> <c- o>*=</c-> <c- mi>2</c-><c- p>;</c-> <c- p>}</c-> <c- k>return</c-> <c- n>v3copy</c-><c- p>;</c->
<c- p>}</c->
<c- k>auto</c-><c- o>&amp;&amp;</c-> <c- p>[</c-><c- n>v3copy</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>then3</c-><c- p>).</c-><c- n>value</c-><c- p>();</c->
<c- c1>// v3 contains {1, 2, 3, 4, 5}; v3copy will contain {2, 4, 6, 8, 10}.</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd4</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- p>{</c-><c- mi>1</c-><c- p>,</c-> <c- mi>2</c-><c- p>,</c-> <c- mi>3</c-><c- p>,</c-> <c- mi>4</c-><c- p>,</c-> <c- mi>5</c-><c- p>});</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then4</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd4</c-><c- p>,</c-> <c- p>[]</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>&amp;&amp;</c-> <c- n>v4</c-><c- p>)</c-> <c- p>{</c->
  <c- k>for</c-> <c- p>(</c-><c- k>auto</c-><c- o>&amp;&amp;</c-> <c- nl>e</c-> <c- p>:</c-> <c- n>v4</c-><c- p>)</c-> <c- p>{</c-> <c- n>e</c-> <c- o>*=</c-> <c- mi>2</c-><c- p>;</c-> <c- p>}</c->
  <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>v4</c-><c- p>);</c->
<c- p>});</c->
<c- k>auto</c-><c- o>&amp;&amp;</c-> <c- p>[</c-><c- n>v4</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>then4</c-><c- p>).</c-><c- n>value</c-><c- p>();</c->
<c- c1>// v4 contains {2, 4, 6, 8, 10}.</c->
</pre>
   <h4 class="heading settled" data-level="4.19.3" id="design-sender-factory-transfer_just"><span class="secno">4.19.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code></span><a class="self-link" href="#design-sender-factory-transfer_just"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>transfer_just</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>scheduler</c-><c- p>,</c->
    <c- k>auto</c-> <c- p>...</c-><c- o>&amp;&amp;</c-> <c- n>values</c->
<c- p>);</c->
</pre>
   <p>Returns a sender whose value <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers④">completion scheduler</a> is the provided scheduler, which <a data-link-type="dfn" href="#send" id="ref-for-send③">sends</a> the provided values in the same manner as <code class="highlight"><c- n>just</c-></code>.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>vals</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-><c- p>(</c->
    <c- n>get_system_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>(),</c->
    <c- mi>1</c-><c- p>,</c-> <c- mi>2</c-><c- p>,</c-> <c- mi>3</c->
<c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>vals</c-><c- p>,</c-> <c- p>[](</c-><c- k>auto</c-><c- p>...</c-> <c- n>args</c-><c- p>)</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>print</c-><c- p>(</c-><c- n>args</c-><c- p>...);</c->
<c- p>});</c->
<c- c1>// when snd is executed, it will print "123"</c->
</pre>
   <p>This adaptor is included as it greatly simplifies lifting values into senders.</p>
   <h4 class="heading settled" data-level="4.19.4" id="design-sender-factory-just_error"><span class="secno">4.19.4. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code></span><a class="self-link" href="#design-sender-factory-just_error"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>just_error</c-><c- p>(</c->
    <c- k>auto</c-> <c- o>&amp;&amp;</c-> <c- n>error</c->
<c- p>);</c->
</pre>
   <p>Returns a sender with no <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers⑤">completion schedulers</a>, which completes with the specified error. If the provided error is an lvalue reference, a copy is made inside the returned sender and a non-const lvalue reference to the copy is sent to the receiver’s <code class="highlight"><c- n>set_error</c-></code>. If the provided value is an rvalue reference, it is moved into the returned sender and an rvalue reference to it is sent to the receiver’s <code class="highlight"><c- n>set_error</c-></code>.</p>
   <h4 class="heading settled" data-level="4.19.5" id="design-sender-factory-just_done"><span class="secno">4.19.5. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code></span><a class="self-link" href="#design-sender-factory-just_done"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>just_done</c-><c- p>();</c->
</pre>
   <p>Returns a sender with no <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers⑥">completion schedulers</a>, which completes immediately by calling the receiver’s <code class="highlight"><c- n>set_done</c-></code>.</p>
   <h3 class="heading settled" data-level="4.20" id="design-sender-adaptors"><span class="secno">4.20. </span><span class="content">User-facing sender adaptors</span><a class="self-link" href="#design-sender-adaptors"></a></h3>
   <p>A <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="sender-adaptor">sender adaptor</dfn> is an <a data-link-type="dfn" href="#algorithm" id="ref-for-algorithm①">algorithm</a> that takes one or more senders, which it may <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, as parameters, and returns a sender, whose completion is related to the sender arguments it has received.</p>
   <p>Sender adaptors are <i>lazy</i>, that is, they are never allowed to submit any work for execution prior to the returned sender being <dfn data-dfn-type="dfn" data-lt="start" data-noexport id="start">started<a class="self-link" href="#start"></a></dfn> later on, and are also guaranteed to not start any input senders passed into them. Sender consumers
such as <a href="#design-sender-adaptor-ensure_started">§ 4.20.13 execution::ensure_started</a>, <a href="#design-sender-consumer-start_detached">§ 4.21.1 execution::start_detached</a>, and <a href="#design-sender-consumer-sync_wait">§ 4.21.2 this_thread::sync_wait</a> start senders.</p>
   <p>For more implementer-centric description of starting senders, see <a href="#design-laziness">§ 5.5 Sender adaptors are lazy</a>.</p>
   <h4 class="heading settled" data-level="4.20.1" id="design-sender-adaptor-transfer"><span class="secno">4.20.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code></span><a class="self-link" href="#design-sender-adaptor-transfer"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>transfer</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>scheduler</c->
<c- p>);</c->
</pre>
   <p>Returns a sender describing the transition from the execution agent of the input sender to the execution agent of the target scheduler. See <a href="#design-transitions">§ 4.6 Execution context transitions are explicit</a>.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>cpu_sched</c-> <c- o>=</c-> <c- n>get_system_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->
<c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>gpu_sched</c-> <c- o>=</c-> <c- n>cuda</c-><c- o>::</c-><c- n>scheduler</c-><c- p>();</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>cpu_task</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>cpu_sched</c-><c- p>);</c->
<c- c1>// cpu_task describes the creation of a new task on the system thread pool</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>gpu_task</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>cpu_task</c-><c- p>,</c-> <c- n>gpu_sched</c-><c- p>);</c->
<c- c1>// gpu_task describes the transition of the task graph described by cpu_task to the gpu</c->
</pre>
   <h4 class="heading settled" data-level="4.20.2" id="design-sender-adaptor-then"><span class="secno">4.20.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code></span><a class="self-link" href="#design-sender-adaptor-then"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>then</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><c- o>&lt;</c-><i><c- n>values</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- p>...</c-><c- o>></c-> <c- n>function</c->
<c- p>);</c->
</pre>
   <p><code class="highlight"><c- n>then</c-></code> returns a sender describing the task graph described by the input sender, with an added node of invoking the provided function with the values <a data-link-type="dfn" href="#send" id="ref-for-send④">sent</a> by the input sender as arguments.</p>
   <p><code class="highlight"><c- n>then</c-></code> is <strong>guaranteed</strong> to not begin executing <code class="highlight"><c- n>function</c-></code> until the returned sender is started.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-> <c- o>=</c-> <c- n>get_input</c-><c- p>();</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>input</c-><c- p>,</c-> <c- p>[](</c-><c- k>auto</c-><c- p>...</c-> <c- n>args</c-><c- p>)</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>print</c-><c- p>(</c-><c- n>args</c-><c- p>...);</c->
<c- p>});</c->
<c- c1>// snd describes the work described by pred</c->
<c- c1>// followed by printing all of the values sent by pred</c->
</pre>
   <p>This adaptor is included as it is necessary for writing any sender code that actually performs a useful function.</p>
   <h4 class="heading settled" data-level="4.20.3" id="design-sender-adaptor-upon"><span class="secno">4.20.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_</c-><c- o>*</c-></code></span><a class="self-link" href="#design-sender-adaptor-upon"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>upon_error</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><c- o>&lt;</c-><i><c- n>errors</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- p>...</c-><c- o>></c-> <c- n>function</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>upon_done</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-> <c- k>auto</c-> <c- n>function</c->
<c- p>);</c->
</pre>
   <p><code class="highlight"><c- n>upon_error</c-></code> and <code class="highlight"><c- n>upon_done</c-></code> are similar to <code class="highlight"><c- n>then</c-></code>, but where <code class="highlight"><c- n>then</c-></code> works with values sent by the input sender, <code class="highlight"><c- n>upon_error</c-></code> works with errors, and <code class="highlight"><c- n>upon_done</c-></code> is invoked when the "done" signal is sent.</p>
   <h4 class="heading settled" data-level="4.20.4" id="design-sender-adaptor-let"><span class="secno">4.20.4. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_</c-><c- o>*</c-></code></span><a class="self-link" href="#design-sender-adaptor-let"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>let_value</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><c- o>&lt;</c-><i><c- n>values</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- p>...</c-><c- o>></c-> <c- n>function</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>let_error</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><c- o>&lt;</c-><i><c- n>errors</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- p>...</c-><c- o>></c-> <c- n>function</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>let_done</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-> <c- k>auto</c-> <c- n>function</c->
<c- p>);</c->
</pre>
   <p><code class="highlight"><c- n>let_value</c-></code> is very similar to <code class="highlight"><c- n>then</c-></code>: when it is started, it invokes the provided function with the values <a data-link-type="dfn" href="#send" id="ref-for-send⑤">sent</a> by the input sender as arguments. However, where the sender returned from <code class="highlight"><c- n>then</c-></code> sends exactly what that function ends up returning - <code class="highlight"><c- n>let_value</c-></code> requires that the function return a sender, and the sender returned by <code class="highlight"><c- n>let_value</c-></code> sends the values sent by the sender returned from the callback. This is similar to the notion of "future unwrapping" in future/promise-based frameworks.</p>
   <p><code class="highlight"><c- n>let_value</c-></code> is <strong>guaranteed</strong> to not begin executing <code class="highlight"><c- n>function</c-></code> until the returned sender is started.</p>
   <p><code class="highlight"><c- n>let_error</c-></code> and <code class="highlight"><c- n>let_done</c-></code> are similar to <code class="highlight"><c- n>let_value</c-></code>, but where <code class="highlight"><c- n>let_value</c-></code> works with values sent by the input sender, <code class="highlight"><c- n>let_error</c-></code> works with errors, and <code class="highlight"><c- n>let_done</c-></code> is invoked when the "done" signal is sent.</p>
   <h4 class="heading settled" data-level="4.20.5" id="design-sender-adaptor-on"><span class="secno">4.20.5. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code></span><a class="self-link" href="#design-sender-adaptor-on"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>on</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sched</c-><c- p>,</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c->
<c- p>);</c->
</pre>
   <p>Returns a sender which, when started, will start the provided sender on an execution agent belonging to the execution context associated with the provided scheduler. This returned sender has no <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers⑦">completion schedulers</a>.</p>
   <h4 class="heading settled" data-level="4.20.6" id="design-sender-adaptor-into_variant"><span class="secno">4.20.6. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code></span><a class="self-link" href="#design-sender-adaptor-into_variant"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>into_variant</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c->
<c- p>);</c->
</pre>
   <p>Returns a sender which sends a variant of tuples of all the possible sets of types sent by the input sender. Senders can send multiple sets of values depending on runtime conditions; this is a helper function that turns them into a single variant value.</p>
   <h4 class="heading settled" data-level="4.20.7" id="design-sender-adaptor-done_as_optional"><span class="secno">4.20.7. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code></span><a class="self-link" href="#design-sender-adaptor-done_as_optional"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>done_as_optional</c-><c- p>(</c->
    <i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i> <c- k>auto</c-> <c- n>snd</c->
<c- p>);</c->
</pre>
   <p>Returns a sender that maps the value channel from a <code class="highlight"><c- n>T</c-></code> to an <code class="highlight"><c- n>optional</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code>, and maps the done channel to a value of an empty <code class="highlight"><c- n>optional</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code>.</p>
   <h4 class="heading settled" data-level="4.20.8" id="design-sender-adaptor-done_as_error"><span class="secno">4.20.8. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code></span><a class="self-link" href="#design-sender-adaptor-done_as_error"></a></h4>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>move_constructible</c-> <c- n>Error</c-><c- o>></c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>done_as_error</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-><c- p>,</c->
    <c- n>Error</c-> <c- n>err</c-> <c- o>=</c-> <c- n>Error</c-><c- p>{}</c->
<c- p>);</c->
</pre>
   <p>Returns a sender that maps the done channel to an error of <code class="highlight"><c- n>err</c-></code>.</p>
   <h4 class="heading settled" data-level="4.20.9" id="design-sender-adaptor-bulk"><span class="secno">4.20.9. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code></span><a class="self-link" href="#design-sender-adaptor-bulk"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>bulk</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>input</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>integral</c-> <c- k>auto</c-> <c- n>size</c-><c- p>,</c->
    <c- n>invocable</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>size</c-><c- p>),</c-> <i><c- n>values</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- p>...</c-><c- o>></c-> <c- n>function</c->
<c- p>);</c->
</pre>
   <p>Returns a sender describing the task of invoking the provided function with every index in the provided shape along with the values sent by the input sender. The returned sender completes once all invocations have completed, or an error has occurred. If it completes
by sending values, they are equivalent to those sent by the input sender.</p>
   <p>No instance of <code class="highlight"><c- n>function</c-></code> will begin executing until the returned sender is started. Each invocation of <code class="highlight"><c- n>function</c-></code> runs in an execution agent whose forward progress guarantees are determined by the scheduler on which they are run. All agents created by a single use
of <code class="highlight"><c- n>bulk</c-></code> execute with the same guarantee. This allows, for instance, a scheduler to execute all invocations of the function in parallel.</p>
   <p>The <code class="highlight"><c- n>bulk</c-></code> operation is intended to be used at the point where the number of agents to be created is known and provided to <code class="highlight"><c- n>bulk</c-></code> via its <code class="highlight"><c- n>shape</c-></code> parameter. For some parallel computations, the number of agents to be created may be a function of the input data or
dynamic conditions of the execution environment. In such cases, <code class="highlight"><c- n>bulk</c-></code> can be combined with additional operations such as <code class="highlight"><c- n>let_value</c-></code> to deliver dynamic shape information to the <code class="highlight"><c- n>bulk</c-></code> operation.</p>
   <p>In this proposal, only integral types are used to specify the shape of the bulk section. We expect that future papers may wish to explore extensions of the interface to explore additional kinds of shapes, such as multi-dimensional grids, that are commonly used for
parallel computing tasks.</p>
   <h4 class="heading settled" data-level="4.20.10" id="design-sender-adaptor-split"><span class="secno">4.20.10. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code></span><a class="self-link" href="#design-sender-adaptor-split"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>split</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c-><c- p>);</c->
</pre>
   <p>If the provided sender is a multi-shot sender, returns that sender. Otherwise, returns a multi-shot sender which sends values equivalent to the values sent by the provided sender. See <a href="#design-shot">§ 4.7 Senders can be either multi-shot or single-shot</a>.</p>
   <h4 class="heading settled" data-level="4.20.11" id="design-sender-adaptor-when_all"><span class="secno">4.20.11. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code></span><a class="self-link" href="#design-sender-adaptor-when_all"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>when_all</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- p>...</c-><c- n>inputs</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>when_all_with_variant</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- p>...</c-><c- n>inputs</c->
<c- p>);</c->
</pre>
   <p><code class="highlight"><c- n>when_all</c-></code> returns a sender which completes once all of the input senders have completed. The values send by this sender are the values sent by each of the input, in order of the arguments passed to <code class="highlight"><c- n>when_all</c-></code>.</p>
   <p><code class="highlight"><c- n>when_all_with_variant</c-></code> does the same, but it adapts all the input senders using <code class="highlight"><c- n>into_variant</c-></code>.</p>
   <p>The returned sender has no <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers⑧">completion schedulers</a>.</p>
   <p>See <a href="#design-join">§ 4.9 Senders are joinable</a>.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sched</c-> <c- o>=</c-> <c- n>get_thread_pool</c-><c- p>().</c-><c- n>scheduler</c-><c- p>();</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sends_1</c-> <c- o>=</c-> <c- p>...;</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sends_abc</c-> <c- o>=</c-> <c- p>...;</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>both</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>when_all</c-><c- p>(</c-><c- n>sched</c-><c- p>,</c->
    <c- n>sends_1</c-><c- p>,</c->
    <c- n>sends_abc</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- k>final</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>both</c-><c- p>,</c-> <c- p>[](</c-><c- k>auto</c-><c- p>...</c-> <c- n>args</c-><c- p>){</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>format</c-><c- p>(</c-><c- s>"the two args: {}, {}"</c-><c- p>,</c-> <c- n>args</c-><c- p>...);</c->
<c- p>});</c->
<c- c1>// when final executes, it will print "the two args: 1, abc"</c->
</pre>
   <h4 class="heading settled" data-level="4.20.12" id="design-sender-adaptor-transfer_when_all"><span class="secno">4.20.12. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code></span><a class="self-link" href="#design-sender-adaptor-transfer_when_all"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>transfer_when_all</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sched</c-><c- p>,</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- p>...</c-><c- n>inputs</c->
<c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>transfer_when_all_with_variant</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>sched</c-><c- p>,</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- p>...</c-><c- n>inputs</c->
<c- p>);</c->
</pre>
   <p>Similar to <a href="#design-sender-adaptor-when_all">§ 4.20.11 execution::when_all</a>, but returns a sender whose value <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers⑨">completion scheduler</a> is the provided scheduler.</p>
   <p>See <a href="#design-join">§ 4.9 Senders are joinable</a>.</p>
   <h4 class="heading settled" data-level="4.20.13" id="design-sender-adaptor-ensure_started"><span class="secno">4.20.13. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code></span><a class="self-link" href="#design-sender-adaptor-ensure_started"></a></h4>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>ensure_started</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c->
<c- p>);</c->
</pre>
   <p>Once <code class="highlight"><c- n>ensure_started</c-></code> returns, it is known that the provided sender has been <a data-link-type="dfn" href="#connect" id="ref-for-connect">connected</a> and <code class="highlight"><c- n>start</c-></code> has been called on the resulting operation state (see <a href="#design-states">§ 5.2 Operation states represent work</a>); in other words, the work described by the provided sender has been submitted
for execution on the appropriate execution contexts. Returns a sender which completes when the provided sender completes and sends values equivalent to those of the provided sender.</p>
   <p>If the returned sender is destroyed before <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>()</c-></code> is called, or if <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>()</c-></code> is called but the
returned operation-state is destroyed before <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>()</c-></code> is called, then a stop-request is sent to the eagerly launched
operation and the operation is detached and will run to completion in the background. Its result will be discarded when it
eventually completes.</p>
   <p>Note that the application will need to make sure that resources are kept alive in the case that the operation detaches.
e.g. by holding a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-></code> to those resources or otherwise having some out-of-band way to signal completion of
the operation so that resource release can be sequenced after the completion.</p>
   <h3 class="heading settled" data-level="4.21" id="design-sender-consumers"><span class="secno">4.21. </span><span class="content">User-facing sender consumers</span><a class="self-link" href="#design-sender-consumers"></a></h3>
   <p>A <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="sender-consumer">sender consumer</dfn> is an <a data-link-type="dfn" href="#algorithm" id="ref-for-algorithm②">algorithm</a> that takes one or more senders, which it may <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, as parameters, and does not return a sender.</p>
   <h4 class="heading settled" data-level="4.21.1" id="design-sender-consumer-start_detached"><span class="secno">4.21.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code></span><a class="self-link" href="#design-sender-consumer-start_detached"></a></h4>
<pre class="highlight"><c- b>void</c-> <c- nf>start_detached</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c->
<c- p>);</c->
</pre>
   <p>Like <code class="highlight"><c- n>ensure_started</c-></code>, but does not return a value; if the provided sender sends an error instead of a value, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>terminate</c-></code> is called.</p>
   <h4 class="heading settled" data-level="4.21.2" id="design-sender-consumer-sync_wait"><span class="secno">4.21.2. </span><span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code></span><a class="self-link" href="#design-sender-consumer-sync_wait"></a></h4>
<pre class="highlight"><c- k>auto</c-> <c- nf>sync_wait</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c->
<c- p>)</c-> <c- k>requires</c-> <c- p>(</c-><i><c- n>always</c-><c- o>-</c-><c- n>sends</c-><c- o>-</c-><c- n>same</c-><c- o>-</c-><c- n>values</c-></i><c- p>(</c-><c- n>sender</c-><c- p>))</c->
    <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><i><c- n>values</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-></i><c- p>(</c-><c- n>sender</c-><c- p>)</c-><c- o>>></c-><c- p>;</c->
</pre>
   <p><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> is a sender consumer that submits the work described by the provided sender for execution, similarly to <code class="highlight"><c- n>ensure_started</c-></code>, except that it blocks <b>the current <code class="highlight"><c- n>std</c-><c- o>::</c-><c- kr>thread</c-></code> or thread of <code class="highlight"><c- n>main</c-></code></b> until the work is completed, and returns
an optional tuple of values that were sent by the provided sender on its completion of work. Where <a href="#design-sender-factory-schedule">§ 4.19.1 execution::schedule</a> and <a href="#design-sender-factory-transfer_just">§ 4.19.3 execution::transfer_just</a> are meant to <i>enter</i> the domain of senders, <code class="highlight"><c- n>sync_wait</c-></code> is meant to <i>exit</i> the domain of
senders, retrieving the result of the task graph.</p>
   <p>If the provided sender sends an error instead of values, <code class="highlight"><c- n>sync_wait</c-></code> throws that error as an exception, or rethrows the original exception if the error is of type <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>exception_ptr</c-></code>.</p>
   <p>If the provided sender sends the "done" signal instead of values, <code class="highlight"><c- n>sync_wait</c-></code> returns an empty optional.</p>
   <p>For an explanation of the <code class="highlight"><c- k>requires</c-></code> clause, see <a href="#design-typed">§ 5.8 Most senders are typed</a>. That clause also explains another sender consumer, built on top of <code class="highlight"><c- n>sync_wait</c-></code>: <code class="highlight"><c- n>sync_wait_with_variant</c-></code>.</p>
   <p class="note" role="note"><span>Note:</span> This function is specified inside <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_thread</c-></code>, and not inside <code class="highlight"><c- n>execution</c-></code>. This is because <code class="highlight"><c- n>sync_wait</c-></code> has to block the <i>current</i> execution agent, but determining what the current execution agent is is not reliable. Since the standard
does not specify any functions on the current execution agent other than those in <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_thread</c-></code>, this is the flavor of this function that is being proposed. If C++ ever obtains fibers, for instance, we expect that a variant of this function called <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_fiber</c-><c- o>::</c-><c- n>sync_wait</c-></code> would be provided. We also expect that runtimes with execution agents that use different synchronization mechanisms than <code class="highlight"><c- n>std</c-><c- o>::</c-><c- kr>thread</c-></code>'s will provide their own flavors of <code class="highlight"><c- n>sync_wait</c-></code> as well (assuming their execution agents have the means
to block in a non-deadlock manner).</p>
   <h3 class="heading settled" data-level="4.22" id="design-execute"><span class="secno">4.22. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code></span><a class="self-link" href="#design-execute"></a></h3>
   <p>In addition to the three categories of functions presented above, we also propose to include a convenience function for fire-and-forget eager one-way submission of an invocable to a scheduler, to fulfil the role of one-way executors from P0443.</p>
<pre class="highlight"><c- b>void</c-> <c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-> <c- k>auto</c-> <c- n>sched</c-><c- p>,</c->
    <c- n>std</c-><c- o>::</c-><c- n>invocable</c-><void> <c- k>auto</c-> <c- n>fn</c->
<c- p>);</c->
</void></pre>
   <p>Submits the provided function for execution on the provided scheduler, as-if by:</p>
<pre class="highlight"><c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sched</c-><c- p>);</c->
<c- k>auto</c-> <c- n>work</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- n>fn</c-><c- p>);</c->
<c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-><c- p>(</c-><c- n>work</c-><c- p>);</c->
</pre>
   <h2 class="heading settled" data-level="5" id="design-implementer"><span class="secno">5. </span><span class="content">Design - implementer side</span><a class="self-link" href="#design-implementer"></a></h2>
   <h3 class="heading settled" data-level="5.1" id="design-receivers"><span class="secno">5.1. </span><span class="content">Receivers serve as glue between senders</span><a class="self-link" href="#design-receivers"></a></h3>
   <p>A <dfn data-dfn-type="dfn" data-noexport id="receiver">receiver<a class="self-link" href="#receiver"></a></dfn> is a callback that supports more than one channel. In fact, it supports three of them:</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>set_value</c-></code>, which is the moral equivalent of an <code class="highlight"><c- k>operator</c-><c- p>()</c-></code> or a function call, which signals successful completion of the operation its execution depends on;</p>
    <li data-md>
     <p><code class="highlight"><c- n>set_error</c-></code>, which signals that an error has happened during scheduling of the current work, executing the current work, or at some earlier point in the sender chain; and</p>
    <li data-md>
     <p><code class="highlight"><c- n>set_done</c-></code>, which signals that the operation completed without succeeding (<code class="highlight"><c- n>set_value</c-></code>) and without failing (<code class="highlight"><c- n>set_error</c-></code>). This result is often used to indicate that the operation stopped early, typically because it was asked to do so because the result is no
longer needed.</p>
   </ul>
   <p>Exactly one of these channels must be successfully (i.e. without an exception being thrown) invoked on a receiver before it is destroyed; if a call to <code class="highlight"><c- n>set_value</c-></code> failed with an exception, either <code class="highlight"><c- n>set_error</c-></code> or <code class="highlight"><c- n>set_done</c-></code> must be invoked on the same receiver. These
requirements are know as the <dfn class="dfn-paneled" data-dfn-type="dfn" data-noexport id="receiver-contract">receiver contract</dfn>.</p>
   <p>While the receiver interface may look novel, it is in fact very similar to the interface of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>promise</c-></code>, which provides the first two signals as <code class="highlight"><c- n>set_value</c-></code> and <code class="highlight"><c- n>set_error</c-></code>, and it’s possible to emulate the third channel with lifetime management of the promise.</p>
   <p>Receivers are not a part of the end-user-facing API of this proposal; they are necessary to allow unrelated senders communicate with each other, but the only users who will interact with receivers directly are authors of senders.</p>
   <p>Receivers are what is passed as the second argument to <a href="#design-connect">§ 5.3 execution::connect</a>.</p>
   <h3 class="heading settled" data-level="5.2" id="design-states"><span class="secno">5.2. </span><span class="content">Operation states represent work</span><a class="self-link" href="#design-states"></a></h3>
   <p>An <dfn data-dfn-type="dfn" data-noexport id="operation-state">operation state<a class="self-link" href="#operation-state"></a></dfn> is an object that represents work. Unlike senders, it is not a chaining mechanism; instead, it is a concrete object that packages the work described by a full sender chain, ready to be executed. An operation state is neither movable nor
copyable, and its interface consists of a single algorithm: <code class="highlight"><c- n>start</c-></code>, which serves as the submission point of the work represented by a given operation state.</p>
   <p>Operation states are not a part of the user-facing API of this proposal; they are necessary for implementing sender consumers like <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> and <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code>, and the knowledge of them is necessary to implement senders, so the only users who will
interact with operation states directly are authors of senders and authors of sender algorithms.</p>
   <p>The return value of <a href="#design-connect">§ 5.3 execution::connect</a> must satisfy the operation state concept.</p>
   <h3 class="heading settled" data-level="5.3" id="design-connect"><span class="secno">5.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code></span><a class="self-link" href="#design-connect"></a></h3>
   <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> is a customization point which <dfn class="dfn-paneled" data-dfn-type="dfn" data-lt="connect" data-noexport id="connect">connects</dfn> senders with receivers, resulting in an operation state that will ensure that the <a data-link-type="dfn" href="#receiver-contract" id="ref-for-receiver-contract">receiver contract</a> of the receiver passed to <code class="highlight"><c- n>connect</c-></code> will be fulfilled.</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>snd</c-> <c- o>=</c-> <i><c- n>some</c-> <c- n>input</c-> <c- n>sender</c-></i><c- p>;</c->
<c- n>execution</c-><c- o>::</c-><c- n>receiver</c-> <c- k>auto</c-> <c- n>rcv</c-> <c- o>=</c-> <i><c- n>some</c-> <c- n>receiver</c-></i><c- p>;</c->
<c- n>execution</c-><c- o>::</c-><c- n>operation_state</c-> <c- k>auto</c-> <c- n>state</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- n>rcv</c-><c- p>);</c->

<c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>state</c-><c- p>);</c->
<c- c1>// at this point, it is guaranteed that the work represented by state has been submitted</c->
<c- c1>// to an execution context, and that execution context will eventually fulfill the</c->
<c- c1>// receiver contract of rcv</c->

<c- c1>// operation states are not movable, and therefore this operation state object must be</c->
<c- c1>// kept alive until the operation finishes</c->
</pre>
   <h3 class="heading settled" data-level="5.4" id="design-customization"><span class="secno">5.4. </span><span class="content">Sender algorithms are customizable</span><a class="self-link" href="#design-customization"></a></h3>
   <p>Senders being able to advertise what their <a data-link-type="dfn" href="#completion-schedulers" id="ref-for-completion-schedulers①⓪">completion schedulers</a> are fulfills one of the promises of senders: that of being able to customize an implementation of a sender algorithm based on what scheduler any work it depends on will complete on.</p>
   <p>The simple way to provide customizations for functions like <code class="highlight"><c- n>then</c-></code>, that is for <a data-link-type="dfn" href="#sender-adaptor" id="ref-for-sender-adaptor①">sender adaptors</a> and <a data-link-type="dfn" href="#sender-consumer" id="ref-for-sender-consumer①">sender consumers</a>, is to follow the customization scheme that has been adopted for C++20 ranges library; to do that, we would define
the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>sender</c-><c- p>,</c-> <c- n>invocable</c-><c- p>)</c-></code> to be equivalent to:</p>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>sender</c-><c- p>.</c-><c- n>then</c-><c- p>(</c-><c- n>invocable</c-><c- p>)</c-></code>, if that expression is well formed; otherwise</p>
    <li data-md>
     <p><code class="highlight"><c- n>then</c-><c- p>(</c-><c- n>sender</c-><c- p>,</c-> <c- n>invocable</c-><c- p>)</c-></code>, performed in a context where this call always performs ADL, if that expression is well formed; otherwise</p>
    <li data-md>
     <p>a default implementation of <code class="highlight"><c- n>then</c-></code>, which returns a sender adaptor, and then define the exact semantics of said adaptor.</p>
   </ol>
   <p>However, this definition is problematic. Imagine another sender adaptor, <code class="highlight"><c- n>bulk</c-></code>, which is a structured abstraction for a loop over an index space. Its default implementation is just a for loop. However, for accelerator runtimes like CUDA, we would like sender algorithms
like <code class="highlight"><c- n>bulk</c-></code> to have specialized behavior, which invokes a kernel of more than one thread (with its size defined by the call to <code class="highlight"><c- n>bulk</c-></code>); therefore, we would like to customize <code class="highlight"><c- n>bulk</c-></code> for CUDA senders to achieve this. However, there’s no reason for CUDA kernels to
necessarily customize the <code class="highlight"><c- n>then</c-></code> sender adaptor, as the generic implementation is perfectly sufficient. This creates a problem, though; consider the following snippet:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>cuda_sch</c-> <c- o>=</c-> <c- n>cuda_scheduler</c-><c- p>{};</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>initial</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>cuda_sch</c-><c- p>);</c->
<c- c1>// the type of initial is a type defined by the cuda_scheduler</c->
<c- c1>// let’s call it cuda::schedule_sender&lt;></c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>next</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>cuda_sch</c-><c- p>,</c-> <c- p>[]{</c-> <c- k>return</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
<c- c1>// the type of next is a standard-library implementation-defined sender adaptor</c->
<c- c1>// that wraps the cuda sender</c->
<c- c1>// let’s call it execution::then_sender_adaptor&lt;cuda::schedule_sender&lt;>></c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>kernel_sender</c-> <c- o>=</c-> <c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>(</c-><c- n>next</c-><c- p>,</c-> <c- n>shape</c-><c- p>,</c-> <c- p>[](</c-><c- b>int</c-> <c- n>i</c-><c- p>){</c-> <c- p>...</c-> <c- p>});</c->
</pre>
   <p>How can we specialize the <code class="highlight"><c- n>bulk</c-></code> sender adaptor for our wrapped <code class="highlight"><c- n>schedule_sender</c-></code>? Well, here’s one possible approach, taking advantage of ADL (and the fact that the definition of "associated namespace" also recursively enumerates the associated namespaces of all template
parameters of a type):</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>cuda</c-><c- o>::</c-><c- n>for_adl_purposes</c-> <c- p>{</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-><c- p>...</c-> <c- n>SentValues</c-><c- o>></c->
<c- k>class</c-> <c- nc>schedule_sender</c-> <c- p>{</c->
    <c- n>execution</c-><c- o>::</c-><c- n>operation_state</c-> <c- k>auto</c-> <c- n>connect</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>receiver</c-> <c- k>auto</c-> <c- n>rcv</c-><c- p>);</c->
    <c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-> <c- k>auto</c-> <c- n>get_completion_scheduler</c-><c- p>()</c-> <c- k>const</c-><c- p>;</c->
<c- p>};</c->

<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>bulk</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- o>&amp;&amp;</c-> <c- n>input</c-><c- p>,</c->
    <c- n>execution</c-><c- o>::</c-><c- n>shape</c-> <c- k>auto</c-> <c- o>&amp;&amp;</c-> <c- n>shape</c-><c- p>,</c->
    <c- n>invocable</c-><c- o>&lt;</c-><i><c- n>sender</c-><c- o>-</c-><c- n>values</c-><c- p>(</c-><c- n>input</c-><c- p>)</c-></i><c- o>></c-> <c- k>auto</c-> <c- o>&amp;&amp;</c-> <c- n>fn</c-><c- p>)</c->
<c- p>{</c->
    <c- c1>// return a cuda sender representing a bulk kernel launch</c->
<c- p>}</c->
<c- p>}</c-> <c- c1>// namespace cuda::for_adl_purposes</c->
</pre>
   <p>However, if the input sender is not just a <code class="highlight"><c- n>then_sender_adaptor</c-></code> like in the example above, but another sender that overrides <code class="highlight"><c- n>bulk</c-></code> by itself, as a member function, because its author believes they know an optimization for bulk - the specialization above will no
longer be selected, because a member function of the first argument is a better match than the ADL-found overload.</p>
   <p>This means that well-meant specialization of sender algorithms that are entirely scheduler-agnostic can have negative consequences.
The scheduler-specific specialization - which is essential for good performance on platforms providing specialized ways to launch certain sender algorithms - would not be selected in such cases.
But it’s really the scheduler that should control the behavior of sender algorithms when a non-default implementation exists, not the sender. Senders merely describe work; schedulers, however, are the handle to the
runtime that will eventually execute said work, and should thus have the final say in <em>how</em> the work is going to be executed.</p>
   <p>Therefore, we are proposing the following customization scheme (also modified to take <a href="#design-dispatch">§ 5.9 Ranges-style CPOs vs tag_invoke</a> into account): the expression <code class="highlight"><c- n>execution</c-><c- o>::&lt;</c-><c- n>sender</c-><c- o>-</c-><c- n>algorithm</c-><c- o>></c-><c- p>(</c-><c- n>sender</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>, for any given sender algorithm that accepts a sender as its first argument, should be
equivalent to:</p>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- o>&lt;</c-><c- n>sender</c-><c- o>-</c-><c- n>algorithm</c-><c- o>></c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><i><c- n>Signal</c-></i><c- o>></c-><c- p>(</c-><c- n>sender</c-><c- p>),</c-> <c- n>sender</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>, if that expression is well-formed; otherwise</p>
    <li data-md>
     <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- o>&lt;</c-><c- n>sender</c-><c- o>-</c-><c- n>algorithm</c-><c- o>></c-><c- p>,</c-> <c- n>sender</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>, if that expression is well-formed; otherwise</p>
    <li data-md>
     <p>a default implementation, if there exists a default implementation of the given sender algorithm.</p>
   </ol>
   <p>where <code class="highlight"><i><c- n>Signal</c-></i></code> is one of <code class="highlight"><c- n>set_value</c-></code>, <code class="highlight"><c- n>set_error</c-></code>, or <code class="highlight"><c- n>set_done</c-></code>; for most sender algorithms, the completion scheduler for <code class="highlight"><c- n>set_value</c-></code> would be used, but for some (like <code class="highlight"><c- n>upon_error</c-></code> or <code class="highlight"><c- n>let_done</c-></code>), one of the others would be used.</p>
   <p>For sender algorithms which accept concepts other than <code class="highlight"><c- n>sender</c-></code> as their first argument, we propose that the customization scheme remains as it has been in <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> so far, except it should also use <code class="highlight"><c- n>tag_invoke</c-></code>.</p>
   <h3 class="heading settled" data-level="5.5" id="design-laziness"><span class="secno">5.5. </span><span class="content">Sender adaptors are lazy</span><a class="self-link" href="#design-laziness"></a></h3>
   <p>Contrary to early revisions of this paper, we propose to make all sender adaptors perform strictly lazy submission, unless specified otherwise (the one notable exception in this paper is <a href="#design-sender-adaptor-ensure_started">§ 4.20.13 execution::ensure_started</a>, whose sole purpose is to start an
input sender).</p>
   <p><dfn data-dfn-type="dfn" data-noexport id="strictly-lazy-submission">Strictly lazy submission<a class="self-link" href="#strictly-lazy-submission"></a></dfn> means that there is a guarantee that no work is submitted to an execution context before a receiver is connected to a sender, and <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> is called on the resulting operation state.</p>
   <h3 class="heading settled" data-level="5.6" id="design-fusion"><span class="secno">5.6. </span><span class="content">Lazy senders provide optimization opportunities</span><a class="self-link" href="#design-fusion"></a></h3>
   <p>Because lazy senders fundamentally <em>describe</em> work, instead of describing or representing the submission of said work to an execution context, and thanks to the flexibility of the customization of most sender algorithms, they provide an opportunity for fusing
multiple algorithms in a sender chain together, into a single function that can later be submitted for execution by an execution context. There are two ways this can happen.</p>
   <p>The first (and most common) way for such optimizations to happen is thanks to the structure of the implementation: because all the work is done within callbacks invoked on the completion of an earlier sender, recursively up to the original source of computation,
the compiler is able to see a chain of work described using senders as a tree of tail calls, allowing for inlining and removal of most of the sender machinery. In fact, when work is not submitted to execution contexts outside of the current thread of execution,
compilers are capable of removing the senders abstraction entirely, while still allowing for composition of functions across different parts of a program.</p>
   <p>The second way for this to occur is when a sender algorithm is specialized for a specific set of arguments. For instance, we expect that, for senders which are known to have been started already, <a href="#design-sender-adaptor-ensure_started">§ 4.20.13 execution::ensure_started</a> will be an identity transformation,
because the sender algorithm will be specialized for such senders. Similarly, an implementation could recognize two subsequent <a href="#design-sender-adaptor-bulk">§ 4.20.9 execution::bulk</a>s of compatible shapes, and merge them together into a single submission of a GPU kernel.</p>
   <h3 class="heading settled" data-level="5.7" id="design-transition-details"><span class="secno">5.7. </span><span class="content">Execution context transitions are two-step</span><a class="self-link" href="#design-transition-details"></a></h3>
   <p>Because <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> takes a sender as its first argument, it is not actually directly customizable by the target scheduler. This is by design: the target scheduler may not know how to transition <i>from</i> a scheduler such as a CUDA scheduler;
transitioning away from a GPU in an efficient manner requires making runtime calls that are specific to the GPU in question, and the same is usually true for other kinds of accelerators too (or for scheduler running on remote systems). To avoid this problem,
specialized schedulers like the ones mentioned here can still hook into the transition mechanism, and inject a sender which will perform a transition to the regular CPU execution context, so that any sender can be attached to it.</p>
   <p>This, however, is a problem: because customization of sender algorithms must be controlled by the scheduler they will run on (see <a href="#design-customization">§ 5.4 Sender algorithms are customizable</a>), the type of the sender returned from <code class="highlight"><c- n>transfer</c-></code> must be controllable by the target scheduler. Besides, the target
scheduler may itself represent a specialized execution context, which requires additional work to be performed to transition <i>to</i> it. GPUs and remote node schedulers are once again good examples of such schedulers: executing code on their execution contexts
requires making runtime API calls for work submission, and quite possibly for the data movement of the values being sent by the input sender passed into <code class="highlight"><c- n>transfer</c-></code>.</p>
   <p>To allow for such customization from both ends, we propose the inclusion of a secondary transitioning sender adaptor, called <code class="highlight"><c- n>schedule_from</c-></code>. This adaptor is a form of <code class="highlight"><c- n>schedule</c-></code>, but takes an additional, second argument: the input sender. This adaptor is not
meant to be invoked manually by the end users; they are always supposed to invoke <code class="highlight"><c- n>transfer</c-></code>, to ensure that both schedulers have a say in how the transitions are made. Any scheduler that specializes <code class="highlight"><c- n>transfer</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- n>sch</c-><c- p>)</c-></code> shall ensure that the
return value of their customization is equivalent to <code class="highlight"><c- n>schedule_from</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>snd2</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>snd2</c-></code> is a successor of <code class="highlight"><c- n>snd</c-></code> that sends values equivalent to those sent by <code class="highlight"><c- n>snd</c-></code>.</p>
   <p>The default implementation of <code class="highlight"><c- n>transfer</c-><c- p>(</c-><c- n>snd</c-><c- p>,</c-> <c- n>sched</c-><c- p>)</c-></code> is <code class="highlight"><c- n>schedule_from</c-><c- p>(</c-><c- n>sched</c-><c- p>,</c-> <c- n>snd</c-><c- p>)</c-></code>.</p>
   <h3 class="heading settled" data-level="5.8" id="design-typed"><span class="secno">5.8. </span><span class="content">Most senders are typed</span><a class="self-link" href="#design-typed"></a></h3>
   <p>All senders should advertise the types they will <a data-link-type="dfn" href="#send" id="ref-for-send⑥">send</a> when they complete. This is necessary for a number of features, and writing code in a way that’s agnostic of whether an input sender is typed or not in common sender adaptors such as <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> is
hard.</p>
   <p>The mechanism for this advertisement is the same as in <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a>; the way to query the types is through <code class="highlight"><c- n>sender_traits</c-><c- o>::</c-><c- n>value_types</c-><c- o>&lt;</c-><c- n>tuple_like</c-><c- p>,</c-> <c- n>variant_like</c-><c- o>></c-></code>.</p>
   <p><code class="highlight"><c- n>sender_traits</c-><c- o>::</c-><c- n>value_types</c-></code> is a template that takes two arguments: one is a tuple-like template, the other is a variant-like template. The tuple-like argument is required to represent senders sending more than one value (such as <code class="highlight"><c- n>when_all</c-></code>). The variant-like
argument is required to represent senders that choose which specific values to send at runtime.</p>
   <p>There’s a choice made in the specification of <a href="#design-sender-consumer-sync_wait">§ 4.21.2 this_thread::sync_wait</a>: it returns a tuple of values sent by the sender passed to it, wrapped in <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code> to handle the <code class="highlight"><c- n>set_done</c-></code> signal. However, this assumes that those values can be represented as a
tuple, like here:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sends_1</c-> <c- o>=</c-> <c- p>...;</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sends_2</c-> <c- o>=</c-> <c- p>...;</c->
<c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sends_3</c-> <c- o>=</c-> <c- p>...;</c->

<c- k>auto</c-> <c- p>[</c-><c- n>a</c-><c- p>,</c-> <c- n>b</c-><c- p>,</c-> <c- n>c</c-><c- p>]</c-> <c- o>=</c-> <c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-><c- p>(</c->
        <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>sends_1</c-><c- p>),</c->
        <c- n>sends_1</c-><c- p>,</c->
        <c- n>sends_2</c-><c- p>,</c->
        <c- n>sends_3</c->
    <c- p>)).</c-><c- n>value</c-><c- p>();</c->
<c- c1>// a == 1</c->
<c- c1>// b == 2</c->
<c- c1>// c == 3</c->
</pre>
   <p>This works well for senders that always send the same set of arguments. If we ignore the possibility of having a sender that sends different sets of arguments into a receiver, we can specify the "canonical" (i.e. required to be followed by all senders) form of <code class="highlight"><c- n>value_types</c-></code> of a sender which sends <code class="highlight"><c- n>Types</c-><c- p>...</c-></code> to be as follows:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- p>...</c-><c- o>></c-> <c- k>typename</c-> <c- nc>TupleLike</c-><c- o>></c->
<c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>TupleLike</c-><types...><c- p>;</c->
</types...></pre>
   <p>If senders could only ever send one specific set of values, this would probably need to be the required form of <code class="highlight"><c- n>value_types</c-></code> for all senders; defining it otherwise would cause very weird results and should be considered a bug.</p>
   <p>This matter is somewhat complicated by the fact that (1) <code class="highlight"><c- n>set_value</c-></code> for receivers can be overloaded and accept different sets of arguments, and (2) senders are allowed to send multiple different sets of values, depending on runtime conditions, the data they
consumed, and so on. To accomodate this, <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> also includes a second template parameter to <code class="highlight"><c- n>value_types</c-></code>, one that represents a variant-like type. If we permit such senders, we would almost certainly need to require that the canonical form of <code class="highlight"><c- n>value_types</c-></code> for <em>all</em> senders (to ensure consistency in how they are handled, and to avoid accidentally interpreting a user-provided variant as a sender-provided one) sending the different sets of arguments <code class="highlight"><c- n>Types1</c-><c- p>...</c-></code>, <code class="highlight"><c- n>Types2</c-><c- p>...</c-></code>, ..., <code class="highlight"><c- n>TypesN</c-><c- p>...</c-></code> to be as follows:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- p>...</c-><c- o>></c-> <c- k>typename</c-> <c- nc>TupleLike</c-><c- p>,</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- p>...</c-><c- o>></c-> <c- k>typename</c-> <c- nc>VariantLike</c->
<c- o>></c->
<c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>VariantLike</c-><c- o>&lt;</c->
    <c- n>TupleLike</c-><c- o>&lt;</c-><c- n>Types1</c-><c- p>...</c-><c- o>></c-><c- p>,</c->
    <c- n>TupleLike</c-><c- o>&lt;</c-><c- n>Types2</c-><c- p>...</c-><c- o>></c-><c- p>,</c->
    <c- p>...,</c->
    <c- n>TupleLike</c-><c- o>&lt;</c-><c- n>Types3</c-><c- p>...</c-><c- o>></c->
<c- o>></c-><c- p>;</c->
</pre>
   <p>This, however, introduces a couple of complications:</p>
   <ol>
    <li data-md>
     <p>A <code class="highlight"><c- n>just</c-><c- p>(</c-><c- mi>1</c-><c- p>)</c-></code> sender would also need to follow this structure, so the correct type for storing the value sent by it would be <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>></c-></code> or some such. This introduces a lot of compile time overhead for the simplest senders, and this overhead
effectively exists in all places in the code where <code class="highlight"><c- n>value_types</c-></code> is queried, regardless of the tuple-like and variant-like templates passed to it. Such overhead does exist if only the tuple-like parameter exists, but is made much worse by adding this second
wrapping layer.</p>
    <li data-md>
     <p>As a consequence of (1): because <code class="highlight"><c- n>sync_wait</c-></code> needs to store the above type, it can no longer return just a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-></code> for <code class="highlight"><c- n>just</c-><c- p>(</c-><c- mi>1</c-><c- p>)</c-></code>; it has to return <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>></c-></code>. C++ currently does not have an easy way to destructure this; it may get
less awkward with pattern matching, but even then it seems extremely heavyweight to involve variants in this API, and for the purpose of generic code, the kind of the return type of <code class="highlight"><c- n>sync_wait</c-></code> must be the same across all sender types.</p>
   </ol>
   <p>One possible solution to (2) above is to place a requirement on <code class="highlight"><c- n>sync_wait</c-></code> that it can only accept senders which send only a single set of values, therefore removing the need for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-></code> to appear in its API; because of this, we propose to expose both <code class="highlight"><c- n>sync_wait</c-></code>, which is a simple, user-friendly version of the sender consumer, but requires that <code class="highlight"><c- n>value_types</c-></code> have only one possible variant, and <code class="highlight"><c- n>sync_wait_with_variant</c-></code>, which accepts any sender, but returns an optional whose value type is the variant of all the
possible tuples sent by the input sender:</p>
<pre class="highlight"><c- k>auto</c-> <c- nf>sync_wait_with_variant</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c->
<c- p>)</c-> <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>variant</c-><c- o>&lt;</c->
        <c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><i><c- n>values</c-><sub><c- n>0</c-></sub><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-></i><c- p>(</c-><c- n>sender</c-><c- p>)</c-><c- o>></c-><c- p>,</c->
        <c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><i><c- n>values</c-><sub><c- n>1</c-></sub><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-></i><c- p>(</c-><c- n>sender</c-><c- p>)</c-><c- o>></c-><c- p>,</c->
        <c- p>...,</c->
        <c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><i><c- n>values</c-><sub><c- n>n</c-></sub><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-></i><c- p>(</c-><c- n>sender</c-><c- p>)</c-><c- o>></c->
    <c- o>>></c-><c- p>;</c->

<c- k>auto</c-> <c- nf>sync_wait</c-><c- p>(</c->
    <c- n>execution</c-><c- o>::</c-><c- n>sender</c-> <c- k>auto</c-> <c- n>sender</c->
<c- p>)</c-> <c- k>requires</c-> <c- p>(</c-><i><c- n>always</c-><c- o>-</c-><c- n>sends</c-><c- o>-</c-><c- n>same</c-><c- o>-</c-><c- n>values</c-></i><c- p>(</c-><c- n>sender</c-><c- p>))</c->
    <c- o>-></c-> <c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><i><c- n>values</c-><c- o>-</c-><c- n>sent</c-><c- o>-</c-><c- n>by</c-></i><c- p>(</c-><c- n>sender</c-><c- p>)</c-><c- o>>></c-><c- p>;</c->
</pre>
   <h3 class="heading settled" data-level="5.9" id="design-dispatch"><span class="secno">5.9. </span><span class="content">Ranges-style CPOs vs <code class="highlight"><c- n>tag_invoke</c-></code></span><a class="self-link" href="#design-dispatch"></a></h3>
   <p>The contemporary technique for customization in the Standard Library is customization point objects. A customization point object, will it look for member functions and then for nonmember functions with the same name as the customization point, and calls those if
they match. This is the technique used by the C++20 ranges library, and previous executors proposals (<a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> and <a data-link-type="biblio" href="#biblio-p1897r3">[P1897R3]</a>) intended to use it as well. However, it has several unfortunate consequences:</p>
   <ol>
    <li data-md>
     <p>It does not allow for easy propagation of customization points unknown to the adaptor to a wrapped object, which makes writing universal adapter types much harder - and this proposal uses quite a lot of those.</p>
    <li data-md>
     <p>It effectively reserves names globally. Because neither member names nor ADL-found functions can be qualified with a namespace, every customization point object that uses the ranges scheme reserves the name for all types in all namespaces. This is unfortunate
due to the sheer number of customization points already in the paper, but also ones that we are envisioning in the future. It’s also a big problem for one of the operations being proposed already: <code class="highlight"><c- n>sync_wait</c-></code>. We imagine that if, in the future, C++ was to
gain fibers support, we would want to also have <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_fiber</c-><c- o>::</c-><c- n>sync_wait</c-></code>, in addition to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code>. However, because we would want the names to be the same in both cases, we would need to make the names of the customizations not match the
names of the customization points. This is undesirable.</p>
   </ol>
   <p>This paper proposes to instead use the mechanism described in <a data-link-type="biblio" href="#biblio-p1895r0">[P1895R0]</a>: <code class="highlight"><c- n>tag_invoke</c-></code>; the wording for <code class="highlight"><c- n>tag_invoke</c-></code> has been incorporated into the proposed specification in this paper.</p>
   <p>In short, instead of using globally reserved names, <code class="highlight"><c- n>tag_invoke</c-></code> uses the <i>type</i> of the customization point object itself as the mechanism to find customizations. It globally reserves only a single name - <code class="highlight"><c- n>tag_invoke</c-></code> - which itself is used the same way that
ranges-style customization points are used. All other customization points are defined in terms of <code class="highlight"><c- n>tag_invoke</c-></code>. For example, the customization for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> will call <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, instead of attempting
to invoke <code class="highlight"><c- n>s</c-><c- p>.</c-><c- n>sync_wait</c-><c- p>()</c-></code>, and then <code class="highlight"><c- n>sync_wait</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> if the member call is not valid.</p>
   <p>Using <code class="highlight"><c- n>tag_invoke</c-></code> has the following benefits:</p>
   <ol>
    <li data-md>
     <p>It reserves only a single global name, instead of reserving a global name for every customization point object we define.</p>
    <li data-md>
     <p>It is possible to propagate customizations to a subobject, because the information of which customization point is being resolved is in the type of an argument, and not in the name of the function:</p>
<pre class="highlight"><c- c1>// forward most customizations to a subobject</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>Tag</c-><c- p>,</c-> <c- k>typename</c-> <c- p>...</c-><c- n>Args</c-><c- o>></c->
<c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>Tag</c-> <c- o>&amp;&amp;</c-> <c- n>tag</c-><c- p>,</c-> <c- n>wrapper</c-> <c- o>&amp;</c-> <c- n>self</c-><c- p>,</c-> <c- n>Args</c-> <c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>args</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Tag</c-><c- o>></c-><c- p>(</c-><c- n>tag</c-><c- p>)(</c-><c- n>self</c-><c- p>.</c-><c- n>subobject</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Args</c-><c- o>></c-><c- p>(</c-><c- n>args</c-><c- p>)...);</c->
<c- p>}</c->

<c- c1>// but override one of them with a specific value</c->
<c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>specific_customization_point_t</c-><c- p>,</c-> <c- n>wrapper</c-> <c- o>&amp;</c-> <c- n>self</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>self</c-><c- p>.</c-><c- n>some_value</c-><c- p>;</c->
<c- p>}</c->
</pre>
    <li data-md>
     <p>It is possible to pass those as template arguments to types, because the information of which customization point is being resolved is in the type. Similarly to how <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a> defines a polymorphic executor wrapper which accepts a list of properties it
supports, we can imagine scheduler and sender wrappers that accept a list of queries and operations they support. That list can contain the types of the customization point objects, and the polymorphic wrappers can then specialize those customization points on
themselves using <code class="highlight"><c- n>tag_invoke</c-></code>, dispatching to manually constructed vtables containing pointers to specialized implementations for the wrapped objects. For an example of such a polymorphic wrapper, see <code class="highlight"><a href="https://github.com/facebookexperimental/libunifex/blob/1a6fbfc9cc3829356ccbdcf9e8d1f3cc33a6d9e0/include/unifex/any_unique.hpp"><c- n>unifex</c-><c- o>::</c-><c- n>any_unique</c-></a></code> (<a href="https://github.com/facebookexperimental/libunifex/blob/1a6fbfc9cc3829356ccbdcf9e8d1f3cc33a6d9e0/examples/any_unique.cpp">example</a>).</p>
   </ol>
   <h2 class="heading settled" data-level="6" id="spec"><span class="secno">6. </span><span class="content">Specification</span><a class="self-link" href="#spec"></a></h2>
   <p>Much of this wording follows the wording of <a data-link-type="biblio" href="#biblio-p0443r14">[P0443R14]</a>.</p>
   <p><a href="#spec-utilities">§ 7 General utilities library [utilities]</a> is meant to be a diff relative to the wording of the <b>[utilities]</b> clause of <a data-link-type="biblio" href="#biblio-n4885">[N4885]</a>. This diff applies changes from <a data-link-type="biblio" href="#biblio-p1895r0">[P1895R0]</a>.</p>
   <p><a href="#spec-thread">§ 8 Thread support library [thread]</a> is meant to be a diff relative to the wording of the <b>[thread]</b> clause of <a data-link-type="biblio" href="#biblio-n4885">[N4885]</a>. This diff applies changes from <a data-link-type="biblio" href="#biblio-p2175r0">[P2175R0]</a>.</p>
   <p><a href="#spec-execution">§ 9 Execution control library [execution]</a> is meant to be added as a new library clause to the working draft of C++.</p>
   <h2 class="heading settled" data-level="7" id="spec-utilities"><span class="secno">7. </span><span class="content">General utilities library <b>[utilities]</b></span><a class="self-link" href="#spec-utilities"></a></h2>
   <h3 class="heading settled" data-level="7.1" id="spec-function.objects"><span class="secno">7.1. </span><span class="content">Function objects <b>[function.objects]</b></span><a class="self-link" href="#spec-function.objects"></a></h3>
   <h4 class="heading settled" data-level="7.1.1" id="spec-functional.syn"><span class="secno">7.1.1. </span><span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>functional</c-><c- o>></c-></code> synopsis <b>[functional.syn]</b></span><a class="self-link" href="#spec-functional.syn"></a></h4>
   <p>At the end of this subclause, insert the following declarations into the synopsis within <code class="highlight"><c- k>namespace</c-> <c- n>std</c-></code>:</p>
   <ins>
    <blockquote>
<pre class="highlight"><c- c1>// [func.tag_invoke], tag_invoke</c->
<c- kr>inline</c-> <c- k>namespace</c-> <c- n>unspecified</c-> <c- p>{</c->
  <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>unspecified</c-> <c- n>tag_invoke</c-> <c- o>=</c-> <c- n>unspecified</c-><c- p>;</c->
<c- p>}</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>auto</c-><c- o>&amp;</c-> <c- n>Tag</c-><c- o>></c->
  <c- k>using</c-> <c- n>tag_t</c-> <c- o>=</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>Tag</c-><c- p>)</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Tag</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>tag_invocable</c-> <c- o>=</c->
    <c- n>invocable</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>tag_invoke</c-><c- p>),</c-> <c- n>Tag</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Tag</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>nothrow_tag_invocable</c-> <c- o>=</c->
    <c- n>tag_invocable</c-><c- o>&lt;</c-><c- n>Tag</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>is_nothrow_invocable_v</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>tag_invoke</c-><c- p>),</c-> <c- n>Tag</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Tag</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
  <c- k>using</c-> <c- n>tag_invoke_result</c-> <c- o>=</c-> <c- n>invoke_result</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>tag_invoke</c-><c- p>),</c-> <c- n>Tag</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Tag</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Args</c-><c- o>></c->
  <c- k>using</c-> <c- n>tag_invoke_result_t</c-> <c- o>=</c-> <c- n>invoke_result_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>tag_invoke</c-><c- p>),</c-> <c- n>Tag</c-><c- p>,</c-> <c- n>Args</c-><c- p>...</c-><c- o>></c-><c- p>;</c->
</pre>
    </blockquote>
   </ins>
   <h4 class="heading settled" data-level="7.1.2" id="spec-func.tag_invoke"><span class="secno">7.1.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>tag_invoke</c-></code> <b>[func.tag_invoke]</b></span><a class="self-link" href="#spec-func.tag_invoke"></a></h4>
   <p>Insert this section as a new subclause, between Searchers <b>[func.search]</b> and Class template <code class="highlight"><c- n>hash</c-></code> <b>[unord.hash]</b>.</p>
   <ins>
    <blockquote>
     <ol>
      <li data-md>
       <p>The name <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tag_invoke</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>tag</c-></code> and <code class="highlight"><c- n>args</c-><c- p>...</c-></code>, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>tag</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is expression-equivalent to an unqualified call to <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><i><c- n>decay</c-><c- o>-</c-><c- n>copy</c-></i><c- p>(</c-><c- n>tag</c-><c- p>),</c-> <c- n>args</c-><c- p>...)</c-></code> with overload
resolution performed in a context that includes the declaration:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>tag_invoke</c-><c- p>();</c->
</pre>
       <p>and that does not include the the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tag_invoke</c-></code> name.</p>
     </ol>
    </blockquote>
   </ins>
   <h2 class="heading settled" data-level="8" id="spec-thread"><span class="secno">8. </span><span class="content">Thread support library <b>[thread]</b></span><a class="self-link" href="#spec-thread"></a></h2>
   <p class="note" role="note"><span>Note:</span> The specification in this section is incomplete; it does not provide an API specification for the new types added into <code class="highlight"><c- o>&lt;</c-><c- n>stop_token</c-><c- o>></c-></code>. For a less formal specification of the missing pieces, see the "Proposed Changes" section of <a data-link-type="biblio" href="#biblio-p2175r0">[P2175R0]</a>. A future revision
of this paper will contain a full specification for the new types.</p>
   <h3 class="heading settled" data-level="8.1" id="spec-thread.stoptoken"><span class="secno">8.1. </span><span class="content">Stop tokens <b>[thread.stoptoken]</b></span><a class="self-link" href="#spec-thread.stoptoken"></a></h3>
   <h4 class="heading settled" data-level="8.1.1" id="spec-thread.stoptoken.syn"><span class="secno">8.1.1. </span><span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>stop_token</c-><c- o>></c-></code> synopsis <b>[thread.stoptoken.syn]</b></span><a class="self-link" href="#spec-thread.stoptoken.syn"></a></h4>
   <p>At the beginning of this subclause, insert the following declarations into the synopsis within <code class="highlight"><c- k>namespace</c-> <c- n>std</c-></code>:</p>
   <ins>
    <blockquote>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-><c- o>></c-> <c- k>class</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>check</c-><c- o>-</c-><c- n>type</c-><c- o>-</c-><c- n>alias</c-><c- o>-</c-><c- n>exists</c-></i><c- p>;</c-> <c- c1>// exposition-only</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>stoppable_token</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>CB</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>Initializer</c-> <c- o>=</c-> <c- n>CB</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>stoppable_token_for</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>unstoppable_token</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->
</pre>
    </blockquote>
   </ins>
   <p>At the end of this subclause, insert the following declarations into the synopsis of within <code class="highlight"><c- k>namespace</c-> <c- n>std</c-></code>:</p>
   <ins>
    <blockquote>
<pre class="highlight"><c- c1>// [stoptoken.never], class never_stop_token</c->
<c- k>class</c-> <c- nc>never_stop_token</c-><c- p>;</c->

<c- c1>// [stoptoken.inplace], class in_place_stop_token</c->
<c- k>class</c-> <c- nc>in_place_stop_token</c-><c- p>;</c->

<c- c1>// [stopsource.inplace], class in_place_stop_source</c->
<c- k>class</c-> <c- nc>in_place_stop_source</c-><c- p>;</c->

<c- c1>// [stopcallback.inplace], class template in_place_stop_callback</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>Callback</c-><c- o>></c->
<c- k>class</c-> <c- nc>in_place_stop_callback</c-><c- p>;</c->
</pre>
    </blockquote>
   </ins>
   <h4 class="heading settled" data-level="8.1.2" id="spec-thread.stoptoken.concepts"><span class="secno">8.1.2. </span><span class="content">Stop token concepts <b>[thread.stoptoken.concepts]</b></span><a class="self-link" href="#spec-thread.stoptoken.concepts"></a></h4>
   <p>Insert this section as a new subclause between Header <code class="highlight"><c- o>&lt;</c-><c- n>stop_token</c-><c- o>></c-></code> synopsis <b>[thread.stoptoken.syn]</b> and Class <code class="highlight"><c- n>stop_token</c-></code> <b>[stoptoken]</b>.</p>
   <ins>
    <blockquote>
     <ol>
      <li data-md>
       <p>The <code class="highlight"><c- n>stoppable_token</c-></code> concept checks for the basic interface of a “stop token” which is copyable and allows polling to see if stop has been requested and also whether a stop request is possible. It also requires an associated nested template-type-alias, <code class="highlight"><c- n>T</c-><c- o>::</c-><c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-></code>, that identifies the stop-callback type to use to register a callback to be executed if a stop-request is ever made on a stoppable_token of type, <code class="highlight"><c- n>T</c-></code>. The <code class="highlight"><c- n>stoppable_token_for</c-></code> concept checks for a stop token type compatible with a given
callback type. The <code class="highlight"><c- n>unstoppable_token</c-></code> concept checks for a stop token type that does not allow stopping.</p>
     </ol>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>stoppable_token</c-> <c- o>=</c->
    <c- n>copy_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>move_constructible</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>is_nothrow_copy_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>is_nothrow_move_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>equality_comparable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>(</c-><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>token</c-><c- p>)</c-> <c- p>{</c->
      <c- p>{</c-> <c- n>token</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-> <c- p>}</c-> <c- k>noexcept</c-> <c- o>-></c-> <c- n>boolean</c-><c- o>-</c-><c- n>testable</c-><c- p>;</c->
      <c- p>{</c-> <c- n>token</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-> <c- p>}</c-> <c- k>noexcept</c-> <c- o>-></c-> <c- n>boolean</c-><c- o>-</c-><c- n>testable</c-><c- p>;</c->
      <c- k>typename</c-> <i><c- nc>check</c-><c- o>-</c-><c- n>type</c-><c- o>-</c-><c- n>alias</c-><c- o>-</c-><c- n>exists</c-></i><c- o>&lt;</c-><c- n>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>></c-><c- p>;</c->
    <c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>CB</c-><c- p>,</c-> <c- k>typename</c-> <c- nc>Initializer</c-> <c- o>=</c-> <c- n>CB</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>stoppable_token_for</c-> <c- o>=</c->
    <c- n>stoppable_token</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>invocable</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>{</c->
      <c- k>typename</c-> <c- nc>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-><c- p>;</c->
    <c- p>}</c-> <c- o>&amp;&amp;</c->
    <c- n>constructible_from</c-><c- o>&lt;</c-><c- n>CB</c-><c- p>,</c-> <c- n>Initializer</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>constructible_from</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-><c- p>,</c-> <c- n>T</c-><c- p>,</c-> <c- n>Initializer</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>constructible_from</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-><c- p>,</c-> <c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>Initializer</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>constructible_from</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- p>,</c-> <c- n>Initializer</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>constructible_from</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>::</c-><c- k>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-><c- p>,</c-> <c- n>Initializer</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>unstoppable_token</c-> <c- o>=</c->
    <c- n>stoppable_token</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>{</c->
      <c- p>{</c-> <c- n>T</c-><c- o>::</c-><c- n>stop_possible</c-><c- p>()</c-> <c- p>}</c-> <c- o>-></c-> <c- n>boolean</c-><c- o>-</c-><c- n>testable</c-><c- p>;</c->
    <c- p>}</c-> <c- o>&amp;&amp;</c->
    <c- p>(</c-><c- o>!</c-><c- n>T</c-><c- o>::</c-><c- n>stop_possible</c-><c- p>());</c->
</pre>
     <ol start="2">
      <li data-md>
       <p>Let <code class="highlight"><c- n>t</c-></code> and <code class="highlight"><c- n>u</c-></code> be distinct object of type <code class="highlight"><c- n>T</c-></code>. The type <code class="highlight"><c- n>T</c-></code> models <code class="highlight"><c- n>stoppable_token</c-></code> only if:</p>
       <ol>
        <li data-md>
         <p>All copies of a <code class="highlight"><c- n>stoppable_token</c-></code> reference the same logical shared stop state and shall report values consistent with each other.</p>
        <li data-md>
         <p>If <code class="highlight"><c- n>t</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-></code> evaluates to <code class="highlight">false</code> then, if <code class="highlight"><c- n>u</c-></code>, references the same logical shared stop state, <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-></code> shall also subsequently evaluate to <code class="highlight">false</code> and <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code> shall also subsequently evaluate to <code class="highlight">false</code>.</p>
        <li data-md>
         <p>If <code class="highlight"><c- n>t</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code> evaluates to <code class="highlight">true</code> then, if <code class="highlight"><c- n>u</c-></code>, references the same logical shared stop state, <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code> shall also subsequently evaluate to <code class="highlight">true</code> and <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-></code> shall also subsequently evaluate to <code class="highlight">true</code>.</p>
        <li data-md>
         <p>Given a callback-type, CB, and a callback-initializer argument, <code class="highlight"><c- n>init</c-></code>, of type <code class="highlight"><c- n>Initializer</c-></code> then constructing an instance, <code class="highlight"><c- n>cb</c-></code>, of type <code class="highlight"><c- n>T</c-><c- o>::</c-><c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-></code>, passing <code class="highlight"><c- n>t</c-></code> as the first argument and <code class="highlight"><c- n>init</c-></code> as the second argument to the constructor, shall,
if <code class="highlight"><c- n>t</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-></code> is <code class="highlight">true</code>, construct an instance, <code class="highlight"><c- n>callback</c-></code>, of type <code class="highlight"><c- n>CB</c-></code>, direct-initialized with <code class="highlight"><c- n>init</c-></code>, and register callback with <code class="highlight"><c- n>t</c-></code>’s shared stop state such that callback will be invoked with an empty argument list if a stop request is made on
the shared stop state.</p>
         <ol>
          <li data-md>
           <p>If <code class="highlight"><c- n>t</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code> is <code class="highlight">true</code> at the time callback is registered then callback may be invoked immediately inline inside the call to <code class="highlight"><c- n>cb</c-></code>’s constructor.</p>
          <li data-md>
           <p>If callback is invoked then, if <code class="highlight"><c- n>u</c-></code> references the same shared stop state as <code class="highlight"><c- n>t</c-></code>, an evaluation of <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code> will be <code class="highlight">true</code> if the beginning of the invocation of callback strongly-happens-before the evaluation of <code class="highlight"><c- n>u</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>()</c-></code>.</p>
          <li data-md>
           <p>If <code class="highlight"><c- n>t</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>()</c-></code> evaluates to <code class="highlight">false</code> then the construction of <code class="highlight"><c- n>cb</c-></code> is not required to construct and initialize <code class="highlight"><c- n>callback</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Construction of a <code class="highlight"><c- n>T</c-><c- o>::</c-><c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-></code> instance shall only throw exceptions thrown by the initialization of the <code class="highlight"><c- n>CB</c-></code> instance from the value of type <code class="highlight"><c- n>Initializer</c-></code>.</p>
        <li data-md>
         <p>Destruction of the <code class="highlight"><c- n>T</c-><c- o>::</c-><c- n>callback_type</c-><c- o>&lt;</c-><c- n>CB</c-><c- o>></c-></code> object, <code class="highlight"><c- n>cb</c-></code>, removes <code class="highlight"><c- n>callback</c-></code> from the shared stop state such that <code class="highlight"><c- n>callback</c-></code> will not be invoked after the destructor returns.</p>
         <ol>
          <li data-md>
           <p>If <code class="highlight"><c- n>callback</c-></code> is currently being invoked on another thread then the destructor of <code class="highlight"><c- n>cb</c-></code> will block until the invocation of <code class="highlight"><c- n>callback</c-></code> returns such that the return from the invocation of <code class="highlight"><c- n>callback</c-></code> strongly-happens-before the destruction of <code class="highlight"><c- n>callback</c-></code>.</p>
          <li data-md>
           <p>Destruction of a callback <code class="highlight"><c- n>cb</c-></code> shall not block on the completion of the invocation of some other callback registered with the same shared stop state.</p>
         </ol>
       </ol>
     </ol>
    </blockquote>
   </ins>
   <h2 class="heading settled" data-level="9" id="spec-execution"><span class="secno">9. </span><span class="content">Execution control library <b>[execution]</b></span><a class="self-link" href="#spec-execution"></a></h2>
   <ol>
    <li data-md>
     <p>This Clause describes components supporting execution of function objects [function.objects].</p>
    <li data-md>
     <p>The following subclauses describe the requirements, concepts, and components for execution control primitives as summarized in Table 1.</p>
   </ol>
   <table>
    <caption>Table 1: Execution control library summary <b>[tab:execution.summary]</b></caption>
    <tbody>
     <tr>
      <th>
      <td>Subclause
      <td>Header
     <tr style="border-bottom-style: hidden;">
      <td><a href="#spec-execution.schedulers">[execution.schedulers]</a>
      <td>Schedulers
      <td><code class="highlight"><c- o>&lt;</c-><c- n>execution</c-><c- o>></c-></code>
     <tr style="border-bottom-style: hidden;">
      <td><a href="#spec-execution.receivers">[execution.receivers]</a>
      <td>Receivers
      <td>
     <tr style="border-bottom-style: hidden;">
      <td><a href="#spec-execution.op_state">[execution.op_state]</a>
      <td>Operation states
      <td>
     <tr style="border-bottom-style: hidden;">
      <td><a href="#spec-execution.senders">[execution.senders]</a>
      <td>Senders
      <td>
     <tr>
      <td><a href="#spec-execution.execute">[execution.execute]</a>
      <td>One-way execution
      <td>
   </table>
   <h3 class="heading settled" data-level="9.1" id="spec-execution.syn"><span class="secno">9.1. </span><span class="content">Header <code class="highlight"><c- o>&lt;</c-><c- n>execution</c-><c- o>></c-></code> synopsis <b>[execution.syn]</b></span><a class="self-link" href="#spec-execution.syn"></a></h3>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-> <c- p>{</c->
  <c- c1>// [execution.helpers], helper concepts</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
    <c- k>concept</c-> <i><c- nc>moveable</c-><c- o>-</c-><c- n>value</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- c1>// [execution.schedulers], schedulers</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>scheduler</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- c1>// [execution.schedulers.queries], scheduler queries</c->
  <c- k>enum</c-> <c- k>class</c-> <c- nc>forward_progress_guarantee</c-><c- p>;</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>get_forward_progress_guarantee_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>get_forward_progress_guarantee_t</c-> <c- n>get_forward_progress_guarantee</c-><c- p>{};</c->
  <c- p>}</c->
<c- p>}</c->

<c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>this_thread</c-> <c- p>{</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>execute_may_block_caller_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>execute_may_block_caller_t</c-> <c- n>execute_may_block_caller</c-><c- p>{};</c->
  <c- p>}</c->
<c- p>}</c->

<c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-> <c- p>{</c->
  <c- c1>// [execution.receivers], receivers</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-> <c- nc>E</c-> <c- o>=</c-> <c- n>exception_ptr</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>receiver</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>An</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>receiver_of</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>set_value_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>set_value_t</c-> <c- n>set_value</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>set_error_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>set_error_t</c-> <c- n>set_error</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>set_done_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>set_done_t</c-> <c- n>set_done</c-><c- p>{};</c->
  <c- p>}</c->

  <c- c1>// [execution.receivers.queries], receiver queries</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>get_scheduler_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>get_scheduler_t</c-> <c- n>get_scheduler</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>get_allocator_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>get_allocator_t</c-> <c- n>get_allocator</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>get_stop_token_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>get_stop_token_t</c-> <c- n>get_stop_token</c-><c- p>{};</c->
  <c- p>}</c->

  <c- c1>// [execution.op_state], operation states</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>O</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>operation_state</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>start_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>start_t</c-> <c- n>start</c-><c- p>{};</c->
  <c- p>}</c->

  <c- c1>// [execution.senders], senders</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>sender</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- p>,</c-> <c- k>class</c-> <c- nc>R</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>sender_to</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>concept</c-> <i><c- nc>has</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>types</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>typed_sender</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
    <c- k>struct</c-> <i><c- nc>type</c-><c- o>-</c-><c- n>list</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- p>,</c-> <c- k>class</c-> <c- p>...</c-><c- n>Ts</c-><c- o>></c->
    <c- k>concept</c-> <c- nc>sender_of</c-> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>using</c-> <i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <i><c- n>see</c-> <c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>concept</c-> <i><c- nc>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i> <c- o>=</c-> <i><c- n>see</c-> <c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- c1>// [execution.senders.traits], sender traits</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>struct</c-> <c- nc>sender_base</c-> <c- p>{};</c->
  <c- p>}</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
    <c- k>struct</c-> <c- nc>sender_traits</c-><c- p>;</c->

  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- c1>// [execution.senders.connect], the connect sender algorithm</c->
    <c- k>struct</c-> <c- nc>connect_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>connect_t</c-> <c- n>connect</c-><c- p>{};</c->

    <c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- p>,</c-> <c- k>class</c-> <c- nc>R</c-><c- o>></c->
      <c- k>using</c-> <c- n>connect_result_t</c-> <c- o>=</c-> <c- k>decltype</c-><c- p>(</c-><c- n>connect</c-><c- p>(</c-><c- n>declval</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>(),</c-> <c- n>declval</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>()));</c->

    <c- c1>// [execution.senders.queries], sender queries</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>CPO</c-><c- o>></c->
    <c- k>struct</c-> <c- nc>get_completion_scheduler_t</c-><c- p>;</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>CPO</c-><c- o>></c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>get_completion_scheduler_t</c-> <c- n>get_completion_scheduler</c-><c- p>{};</c->

    <c- c1>// [execution.senders.factories], sender factories</c->
    <c- k>struct</c-> <c- nc>schedule_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>schedule_t</c-> <c- n>schedule</c-><c- p>{};</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
      <c- k>struct</c-> <i><c- nc>just</c-><c- o>-</c-><c- n>sender</c-></i><c- p>;</c-> <c- c1>// exposition only</c->
    <c- k>template</c-><c- o>&lt;</c-><i><c- n>moveable</c-><c- o>-</c-><c- n>value</c-></i><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
      <i><c- n>just</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>Ts</c-><c- o>></c-><c- p>...</c-><c- o>></c-> <c- n>just</c-><c- p>(</c-><c- n>Ts</c-> <c- o>&amp;&amp;</c-><c- p>...);</c->
    <c- k>struct</c-> <c- nc>transfer_just_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>transfer_just_t</c-> <c- n>transfer_just</c-><c- p>{};</c->

    <c- c1>// [execution.senders.adaptors], sender adaptors</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>D</c-><c- o>></c->
      <c- k>requires</c-> <c- n>is_class_v</c-><c- o>&lt;</c-><c- n>D</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>same_as</c-><c- o>&lt;</c-><c- n>D</c-><c- p>,</c-> <c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>D</c-><c- o>>></c->
      <c- k>struct</c-> <c- nc>sender_adaptor_closure</c-> <c- p>{</c-> <c- p>};</c->

    <c- k>struct</c-> <c- nc>on_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>on_t</c-> <c- n>on</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>transfer_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>transfer_t</c-> <c- n>transfer</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>schedule_from_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>schedule_from_t</c-> <c- n>schedule_from</c-><c- p>{};</c->

    <c- k>struct</c-> <c- nc>then_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>then_t</c-> <c- n>then</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>upon_error_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>upon_error_t</c-> <c- n>upon_error</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>upon_done_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>upon_done_t</c-> <c- n>upon_done</c-><c- p>{};</c->

    <c- k>struct</c-> <c- nc>let_value_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>let_value_t</c-> <c- n>let_value</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>let_error_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>let_error_t</c-> <c- n>let_error</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>let_done_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>let_done_t</c-> <c- n>let_done</c-><c- p>{};</c->

    <c- k>struct</c-> <c- nc>bulk_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>bulk_t</c-> <c- n>bulk</c-><c- p>{};</c->

    <c- k>struct</c-> <c- nc>split_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>split_t</c-> <c- n>split</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>when_all_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>when_all_t</c-> <c- n>when_all</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>when_all_with_variant_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>when_all_with_variant_t</c-> <c- n>when_all_with_variant</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>transfer_when_all_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>transfer_when_all_t</c-> <c- n>transfer_when_all</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>transfer_when_all_with_variant_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>transfer_when_all_with_variant_t</c->
      <c- n>transfer_when_all_with_variant</c-><c- p>{};</c->

    <c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
      <c- k>using</c-> <i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition-only</c->
    <c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
      <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>into_variant</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-><c- p>);</c->

    <c- k>struct</c-> <c- nc>done_as_optional_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>done_as_optional_t</c-> <c- n>done_as_optional</c-><c- p>;</c->

    <c- k>template</c-><c- o>&lt;</c-><c- n>move_constructible</c-> <c- n>Error</c-><c- p>,</c-> <c- n>sender</c-> <c- n>S</c-><c- o>></c->
      <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>done_as_error</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-><c- p>,</c-> <c- n>Error</c-> <c- n>err</c-> <c- o>=</c-> <c- n>Error</c-><c- p>{});</c->

    <c- c1>// [execution.senders.consumers], sender consumers</c->
    <c- k>struct</c-> <c- nc>ensure_started_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>ensure_started_t</c-> <c- n>ensure_started</c-><c- p>{};</c->

    <c- k>struct</c-> <c- nc>start_detached_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>start_detached_t</c-> <c- n>start_detached</c-><c- p>{};</c->
  <c- p>}</c->
<c- p>}</c->

<c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>this_thread</c-> <c- p>{</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
      <c- k>using</c-> <i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition-only</c->
    <c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
      <c- k>using</c-> <i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>;</c-> <c- c1>// exposition-only</c->

    <c- k>struct</c-> <c- nc>sync_wait_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>sync_wait_t</c-> <c- n>sync_wait</c-><c- p>{};</c->
    <c- k>struct</c-> <c- nc>sync_wait_with_variant_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>sync_wait_with_variant_t</c-> <c- n>sync_wait_with_variant</c-><c- p>{};</c->
  <c- p>}</c->
<c- p>}</c->

<c- k>namespace</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-> <c- p>{</c->
  <c- kr>inline</c-> <c- k>namespace</c-> <i><c- n>unspecified</c-></i> <c- p>{</c->
    <c- c1>// [execution.execute], one-way execution</c->
    <c- k>struct</c-> <c- nc>execute_t</c-><c- p>;</c->
    <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>execute_t</c-> <c- n>execute</c-><c- p>{};</c->
  <c- p>}</c->

  <c- c1>// [execution.coro_utils.as_awaitable]</c->
  <c- k>template</c-> <c- o>&lt;</c-><i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i> <c- n>Sender</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Promise</c-><c- o>></c->
    <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>as_awaitable</c-><c- p>(</c-><c- n>Sender</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>Promise</c-><c- o>&amp;</c-> <c- n>p</c-><c- p>);</c->

  <c- c1>// [execution.coro_utils.with_awaitable_senders]</c->
  <c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>Promise</c-><c- o>></c->
    <c- k>requires</c-> <c- n>is_class_v</c-><c- o>&lt;</c-><c- n>Promise</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>same_as</c-><c- o>&lt;</c-><c- n>Promise</c-><c- p>,</c-> <c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>Promise</c-><c- o>>></c->
    <c- k>struct</c-> <c- nc>with_awaitable_senders</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <h3 class="heading settled" data-level="9.2" id="spec-execution.helpers"><span class="secno">9.2. </span><span class="content">Helper concepts <b>[execution.helpers]</b></span><a class="self-link" href="#spec-execution.helpers"></a></h3>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
<c- k>concept</c-> <c- nc>moveable</c-><c- o>-</c-><c- n>value</c-> <c- o>=</c-> <c- c1>// exposition only</c->
  <c- n>move_constructible</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-> <c- o>&amp;&amp;</c->
  <c- n>constructible_from</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c-> <c- n>T</c-><c- o>></c-><c- p>;</c->
</pre>
   <h3 class="heading settled" data-level="9.3" id="spec-execution.schedulers"><span class="secno">9.3. </span><span class="content">Schedulers <b>[execution.schedulers] </b></span><a class="self-link" href="#spec-execution.schedulers"></a></h3>
   <ol>
    <li data-md>
     <p>The <code class="highlight"><c- n>scheduler</c-></code> concept defines the requirements of a type that allows for scheduling of work on its <i>associated execution context</i>.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>scheduler</c-> <c- o>=</c->
    <c- n>copy_constructible</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-> <c- o>&amp;&amp;</c->
    <c- n>equality_comparable</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-><c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>)</c-> <c- p>{</c->
      <c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-><c- n>s</c-><c- p>);</c->
    <c- p>};</c->
</pre>
    <li data-md>
     <p>None of a scheduler’s copy constructor, destructor, equality comparison, or <code class="highlight"><c- n>swap</c-></code> member functions shall exit via an exception.</p>
    <li data-md>
     <p>None of these member functions, nor a scheduler type’s <code class="highlight"><c- n>schedule</c-></code> function, shall introduce data races as a result of concurrent invocations of those functions from different
threads.</p>
    <li data-md>
     <p>For any two (possibly const) values <code class="highlight"><c- n>s1</c-></code> and <code class="highlight"><c- n>s2</c-></code> of some scheduler type <code class="highlight"><c- n>S</c-></code>, <code class="highlight"><c- n>s1</c-> <c- o>==</c-> <c- n>s2</c-></code> shall return <code class="highlight">true</code> only if both <code class="highlight"><c- n>s1</c-></code> and <code class="highlight"><c- n>s2</c-></code> are handles to the same associated execution context.</p>
    <li data-md>
     <p>A scheduler type’s destructor shall not block pending completion of any receivers connected to the sender objects returned from <code class="highlight"><c- n>schedule</c-></code>. [<i>Note:</i> The ability to wait for completion of submitted function objects may be provided by the associated execution
context of the scheduler. <i>—end note</i>]</p>
   </ol>
   <h4 class="heading settled" data-level="9.3.1" id="spec-execution.schedulers.queries"><span class="secno">9.3.1. </span><span class="content">Scheduler queries <b>[execution.schedulers.queries]</b></span><a class="self-link" href="#spec-execution.schedulers.queries"></a></h4>
   <h5 class="heading settled" data-level="9.3.1.1" id="spec-execution.schedulers.queries.get_forward_progress_guarantee"><span class="secno">9.3.1.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-></code> <b>[execution.schedulers.queries.get_forward_progress_guarantee]</b></span><a class="self-link" href="#spec-execution.schedulers.queries.get_forward_progress_guarantee"></a></h5>
<pre class="highlight"><c- k>enum</c-> <c- k>class</c-> <c- nc>forward_progress_guarantee</c-> <c- p>{</c->
    <c- n>concurrent</c-><c- p>,</c->
    <c- n>parallel</c-><c- p>,</c->
    <c- n>weakly_parallel</c->
<c- p>};</c->
</pre>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-></code> is used to ask a scheduler about the forward progress guarantees of execution agents created by that scheduler.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-></code> is ill-formed.
Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>s</c-><c- p>))</c-></code>, if this expression is well formed and its type is <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>forward_progress_guarantee</c-></code>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>forward_progress_guarantee</c-><c- o>::</c-><c- n>weakly_parallel</c-></code>.</p>
     </ol>
    <li data-md>
     <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_forward_progress_guarantee</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> for some scheduler <code class="highlight"><c- n>s</c-></code> returns <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>forward_progress_guarantee</c-><c- o>::</c-><c- n>concurrent</c-></code>, all execution agents created by that scheduler shall provide the concurrent forward progress guarantee. If it returns <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>forward_progress_guarantee</c-><c- o>::</c-><c- n>parallel</c-></code>, all execution agents created by that scheduler shall provide at least the parallel forward progress guarantee.</p>
   </ol>
   <h5 class="heading settled" data-level="9.3.1.2" id="spec-execution.schedulers.queries.execute_may_block_caller"><span class="secno">9.3.1.2. </span><span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code> <b>[execution.schedulers.queries.execute_may_block_caller</b></span><a class="self-link" href="#spec-execution.schedulers.queries.execute_may_block_caller"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code> is used to ask a scheduler <code class="highlight"><c- n>s</c-></code> whether a call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> with any invocable <code class="highlight"><c- n>f</c-></code> may block the thread where such a call occurs.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>s</c-><c- p>))</c-></code>, if this expression is well formed and its type is <code class="highlight"><c- b>bool</c-></code>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight">true</code>.</p>
     </ol>
    <li data-md>
     <p>If <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>execute_may_block_caller</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> for some scheduler <code class="highlight"><c- n>s</c-></code> returns <code class="highlight">false</code>, no <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> call with some invocable <code class="highlight"><c- n>f</c-></code> shall block the calling thread.</p>
   </ol>
   <h3 class="heading settled" data-level="9.4" id="spec-execution.receivers"><span class="secno">9.4. </span><span class="content">Receivers <b>[execution.receivers]</b></span><a class="self-link" href="#spec-execution.receivers"></a></h3>
   <ol>
    <li data-md>
     <p>A <i>receiver</i> represents the continuation of an asynchronous operation. An asynchronous operation may complete with a (possibly empty) set of values, an error, or it may be cancelled. A receiver has three principal operations corresponding to the three ways
an asynchronous operation may complete: <code class="highlight"><c- n>set_value</c-></code>, <code class="highlight"><c- n>set_error</c-></code>, and <code class="highlight"><c- n>set_done</c-></code>. These are collectively known as a receiver’s <i>completion-signal operations</i>.</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>receiver</c-></code> concept defines the requirements for a receiver type with an unknown set of value types. The <code class="highlight"><c- n>receiver_of</c-></code> concept defines the requirements for a receiver type with a known set of value types, whose error type is <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>exception_ptr</c-></code>.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-> <c- nc>E</c-> <c- o>=</c-> <c- n>exception_ptr</c-><c- o>></c->
<c- k>concept</c-> <c- nc>receiver</c-> <c- o>=</c->
  <c- n>move_constructible</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-> <c- o>&amp;&amp;</c->
  <c- n>constructible_from</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c-> <c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
  <c- k>requires</c-><c- p>(</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>&amp;&amp;</c-> <c- n>t</c-><c- p>,</c-> <c- n>E</c-><c- o>&amp;&amp;</c-> <c- n>e</c-><c- p>)</c-> <c- p>{</c->
    <c- p>{</c-> <c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>t</c-><c- p>))</c-> <c- p>}</c-> <c- k>noexcept</c-><c- p>;</c->
    <c- p>{</c-> <c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>t</c-><c- p>),</c-> <c- p>(</c-><c- n>E</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>e</c-><c- p>)</c-> <c- p>}</c-> <c- k>noexcept</c-><c- p>;</c->
  <c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>An</c-><c- o>></c->
<c- k>concept</c-> <c- nc>receiver_of</c-> <c- o>=</c->
  <c- n>receiver</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c->
  <c- k>requires</c-><c- p>(</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>&amp;&amp;</c-> <c- n>t</c-><c- p>,</c-> <c- n>An</c-><c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>an</c-><c- p>)</c-> <c- p>{</c->
    <c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>t</c-><c- p>),</c-> <c- p>(</c-><c- n>An</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>an</c-><c- p>...);</c->
  <c- p>};</c->
</pre>
    <li data-md>
     <p>The receiver’s completion-signal operations have semantic requirements that are collectively known as the <i>receiver contract</i>, described below:</p>
     <ol>
      <li data-md>
       <p>None of a receiver’s completion-signal operations shall be invoked before <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> has been called on the operation state object that was returned by <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> to connect that receiver to a sender.</p>
      <li data-md>
       <p>Once <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> has been called on the operation state object, exactly one of the receiver’s completion-signal operations shall complete non-exceptionally before the receiver is destroyed.</p>
      <li data-md>
       <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> exits with an exception, it is still valid to call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> or <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> on the receiver, but it is no longer valid to call <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> on the receiver.</p>
     </ol>
    <li data-md>
     <p>Once one of a receiver’s completion-signal operations has completed non-exceptionally, the receiver contract has been satisfied.</p>
   </ol>
   <h4 class="heading settled" data-level="9.4.1" id="spec-execution.receivers.set_value"><span class="secno">9.4.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> <b>[execution.receivers.set_value]</b></span><a class="self-link" href="#spec-execution.receivers.set_value"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> is used to send a <i>value completion signal</i> to a receiver.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> denotes a customization point object. The expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>R</c-><c- p>,</c-> <c- n>Vs</c-><c- p>...)</c-></code> for some subexpressions <code class="highlight"><c- n>R</c-></code> and <code class="highlight"><c- n>Vs</c-><c- p>...</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>,</c-> <c- n>R</c-><c- p>,</c-> <c- n>Vs</c-><c- p>...)</c-></code>, if that expression is valid. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not send the value(s) <code class="highlight"><c- n>Vs</c-><c- p>...</c-></code> to the receiver <code class="highlight"><c- n>R</c-></code>’s value channel, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>R</c-><c- p>,</c-> <c- n>Vs</c-><c- p>...)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h4 class="heading settled" data-level="9.4.2" id="spec-execution.receivers.set_error"><span class="secno">9.4.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> <b>[execution.receivers.set_error]</b></span><a class="self-link" href="#spec-execution.receivers.set_error"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> is used to send a <i>error signal</i> to a receiver.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> denotes a customization point object. The expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>R</c-><c- p>,</c-> <c- n>E</c-><c- p>)</c-></code> for some subexpressions <code class="highlight"><c- n>R</c-></code> and <code class="highlight"><c- n>E</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>,</c-> <c- n>R</c-><c- p>,</c-> <c- n>E</c-><c- p>)</c-></code>, if that expression is valid. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not send the error <code class="highlight"><c- n>E</c-></code> to the receiver <code class="highlight"><c- n>R</c-></code>’s error channel, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>R</c-><c- p>,</c-> <c- n>E</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h4 class="heading settled" data-level="9.4.3" id="spec-execution.receivers.set_done"><span class="secno">9.4.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> <b>[execution.receivers.set_done]</b></span><a class="self-link" href="#spec-execution.receivers.set_done"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> is used to send a <i>done signal</i> to a receiver.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code> denotes a customization point object. The expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>R</c-><c- p>)</c-></code> for some subexpression <code class="highlight"><c- n>R</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>,</c-> <c- n>R</c-><c- p>)</c-></code>, if that expression is valid. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not signal the receiver <code class="highlight"><c- n>R</c-></code>’s done channel, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>R</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h4 class="heading settled" data-level="9.4.4" id="spec-execution.receivers.queries"><span class="secno">9.4.4. </span><span class="content">Receiver queries <b>[execution.receivers.queries]</b></span><a class="self-link" href="#spec-execution.receivers.queries"></a></h4>
   <h5 class="heading settled" data-level="9.4.4.1" id="spec-execution.receivers.queries.get_scheduler"><span class="secno">9.4.4.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-></code> <b>[execution.receivers.queries.get_scheduler]</b></span><a class="self-link" href="#spec-execution.receivers.queries.get_scheduler"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-></code> is used to ask a receiver object for a <i>suggested scheduler</i> to be used by a sender it is connected to when it needs to launch additional work. [<i>Note:</i> the presence of this query on a receiver does not bind a sender to use
its result. --<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>r</c-></code>, let <code class="highlight"><c- n>R</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>r</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>R</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>receiver</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is
expression equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>r</c-><c- p>))</c-></code>, if this expression is well formed and satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_scheduler</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h5 class="heading settled" data-level="9.4.4.2" id="spec-execution.receivers.queries.get_allocator"><span class="secno">9.4.4.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-></code> <b>[execution.receivers.queries.get_allocator]</b></span><a class="self-link" href="#spec-execution.receivers.queries.get_allocator"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-></code> is used to ask a receiver object for a <i>suggested allocator</i> to be used by a sender it is connected to when it needs to allocate memory. [<i>Note:</i> the presence of this query on a receiver does not bind a sender to use
its result. --<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>r</c-></code>, let <code class="highlight"><c- n>R</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>r</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>R</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>receiver</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is
expression equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>r</c-><c- p>))</c-></code>, if this expression is well formed and models <i>Allocator</i>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_allocator</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h5 class="heading settled" data-level="9.4.4.3" id="spec-execution.receivers.queries.get_stop_token"><span class="secno">9.4.4.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-></code> <b>[execution.receivers.queries.get_stop_token]</b></span><a class="self-link" href="#spec-execution.receivers.queries.get_stop_token"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-></code> is used to ask a receiver object for an <i>associated stop token</i> of that receiver. A sender connected with that receiver can use this stop token to check whether a stop request has been made. [<i>Note</i>: such
a stop token being signalled does not bind the sender to actually cancel any work. --<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>r</c-></code>, let <code class="highlight"><c- n>R</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>r</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>R</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>receiver</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is expression equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>r</c-><c- p>))</c-></code>, if this expression is well formed and satisfies <code class="highlight"><c- n>stoppable_token</c-></code>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>never_stop_token</c-><c- p>{}</c-></code>.</p>
     </ol>
    <li data-md>
     <p>Let <code class="highlight"><c- n>r</c-></code> be a receiver, <code class="highlight"><c- n>s</c-></code> be a sender, and <code class="highlight"><c- n>op_state</c-></code> be an operation state resulting from an <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code> call. Let <code class="highlight"><c- n>token</c-></code> be a stop token resulting from an <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> call. <code class="highlight"><c- n>token</c-></code> must remain valid at least until a call to
a receiver completion-signal function of <code class="highlight"><c- n>r</c-></code> returns successfully. [<i>Note</i>: this means that, unless it knows about further guarantees provided by the receiver <code class="highlight"><c- n>r</c-></code>, the implementation of <code class="highlight"><c- n>op_state</c-></code> should not use <code class="highlight"><c- n>token</c-></code> after it makes a call to a receiver
completion-signal function of <code class="highlight"><c- n>r</c-></code>. This also implies that stop callbacks registered on <code class="highlight"><c- n>token</c-></code> by the implementation of <code class="highlight"><c- n>op_state</c-></code> or <code class="highlight"><c- n>s</c-></code> must be destroyed before such a call to a receiver completion-signal function of <code class="highlight"><c- n>r</c-></code>. --<i>end note</i>]</p>
   </ol>
   <h3 class="heading settled" data-level="9.5" id="spec-execution.op_state"><span class="secno">9.5. </span><span class="content">Operation states <b>[execution.op_state]</b></span><a class="self-link" href="#spec-execution.op_state"></a></h3>
   <ol>
    <li data-md>
     <p>The <code class="highlight"><c- n>operation_state</c-></code> concept defines the requirements for an operation state type, which allows for starting the execution of work.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>O</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>operation_state</c-> <c- o>=</c->
    <c- n>destructible</c-><c- o>&lt;</c-><c- n>O</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>is_object_v</c-><c- o>&lt;</c-><c- n>O</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>(</c-><c- n>O</c-><c- o>&amp;</c-> <c- n>o</c-><c- p>)</c-> <c- p>{</c->
      <c- p>{</c-> <c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>o</c-><c- p>)</c-> <c- p>}</c-> <c- k>noexcept</c-><c- p>;</c->
    <c- p>};</c->
</pre>
   </ol>
   <h4 class="heading settled" data-level="9.5.1" id="spec-execution.op_state.start"><span class="secno">9.5.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> <b>[execution.op_state.start]</b></span><a class="self-link" href="#spec-execution.op_state.start"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> is used to start work represented by an operation state object.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> denotes a customization point object. The expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-></code> for some lvalue subexpression <code class="highlight"><c- n>O</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>,</c-> <c- n>O</c-><c- p>)</c-></code>, if that expression is valid. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not start the work represented by the operation state <code class="highlight"><c- n>O</c-></code>, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
    <li data-md>
     <p>The caller of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-></code> must guarantee that the lifetime of the operation state object <code class="highlight"><c- n>O</c-></code> extends at least until one of the receiver completion-signal functions of a receiver <code class="highlight"><c- n>R</c-></code> passed into the <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> call that produced <code class="highlight"><c- n>O</c-></code> is ready
to successfully return. [<i>Note:</i> this allows for the receiver to manage the lifetime of the operation state object, if destroying it is the last operation it performs in its completion-signal functions. --<i>end note</i>]</p>
   </ol>
   <h3 class="heading settled" data-level="9.6" id="spec-execution.senders"><span class="secno">9.6. </span><span class="content">Senders <b>[execution.senders]</b></span><a class="self-link" href="#spec-execution.senders"></a></h3>
   <ol>
    <li data-md>
     <p>A sender describes a potentially asynchronous operation. A sender’s responsibility is to fulfill the receiver contract of a connected receiver by delivering one of the receiver completion-signals.</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>sender</c-></code> concept defines the requirements for a sender type. The <code class="highlight"><c- n>sender_to</c-></code> concept defines the requirements for a sender type capable of being connected with a specific receiver type.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>sender</c-> <c- o>=</c->
    <c- n>move_constructible</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-> <c- o>&amp;&amp;</c->
    <c- o>!</c-><c- k>requires</c-> <c- p>{</c->
      <c- k>typename</c-> <c- nc>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>>::</c-><c- n>__unspecialized</c-><c- p>;</c-> <c- c1>// exposition only</c->
    <c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- p>,</c-> <c- k>class</c-> <c- nc>R</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>sender_to</c-> <c- o>=</c->
    <c- n>sender</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>R</c-><c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
      <c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-><c- p>,</c-> <c- p>(</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>);</c->
    <c- p>};</c->
</pre>
    <li data-md>
     <p>A sender is <i>typed</i> if it declares what types it sends through a connected receiver’s channels.</p>
    <li data-md>
     <p>The <code class="highlight"><c- n>typed_sender</c-></code> concept defines the requirements for a typed sender type.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>concept</c-> <i><c- nc>has</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>types</c-></i> <c- o>=</c-> <c- c1>// exposition only</c->
    <c- k>requires</c-> <c- p>{</c->
      <c- k>typename</c-> <i><c- nc>has</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>types</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>::</c-><c- k>template</c-> <c- n>value_types</c-><c- o>></c-><c- p>;</c->
      <c- k>typename</c-> <i><c- nc>has</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>types</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>::</c-><c- k>template</c-> <c- n>error_types</c-><c- o>></c-><c- p>;</c->
      <c- k>typename</c-> <c- nc>bool_constant</c-><c- o>&lt;</c-><c- n>S</c-><c- o>::</c-><c- n>sends_done</c-><c- o>></c-><c- p>;</c->
    <c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>typed_sender</c-> <c- o>=</c->
    <c- n>sender</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <i><c- n>has</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>types</c-></i><c- o>&lt;</c-><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>>></c-><c- p>;</c->
</pre>
    <li data-md>
     <p>The <code class="highlight"><c- n>sender_of</c-></code> concept defines the requirements for a typed sender type that on successful completion sends the specified set of value types.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>type</c-><c- o>-</c-><c- n>list</c-></i> <c- p>{};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- p>,</c-> <c- k>class</c-><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
  <c- k>concept</c-> <c- nc>sender_of</c-> <c- o>=</c->
    <c- n>typed_sender</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- n>same_as</c-><c- o>&lt;</c->
      <i><c- n>type</c-><c- o>-</c-><c- n>list</c-></i><c- o>&lt;</c-><c- n>Ts</c-><c- p>...</c-><c- o>></c-><c- p>,</c->
      <c- k>typename</c-> <c- nc>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>::</c-><c- n>value_types</c-><c- o>&lt;</c-><i><c- n>type</c-><c- o>-</c-><c- n>list</c-></i><c- p>,</c-> <c- n>type_identity_t</c-><c- o>></c->
    <c- o>></c-><c- p>;</c->
</pre>
   </ol>
   <h4 class="heading settled" data-level="9.6.1" id="spec-execution.senders.traits"><span class="secno">9.6.1. </span><span class="content">Sender traits <b>[execution.senders.traits]</b></span><a class="self-link" href="#spec-execution.senders.traits"></a></h4>
   <ol>
    <li data-md>
     <p>The class <code class="highlight"><c- n>sender_base</c-></code> is used as a base class to tag sender types which do not expose member templates <code class="highlight"><c- n>value_types</c-></code>, <code class="highlight"><c- n>error_types</c-></code>, and a static member constant expression <code class="highlight"><c- n>sends_done</c-></code>.</p>
    <li data-md>
     <p>The class template <code class="highlight"><c- n>sender_traits</c-></code> is used to query a sender type for facts associated with the signal it sends.</p>
    <li data-md>
     <p>The primary class template <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> also recognizes awaitables as typed senders. For this clause ([execution]):</p>
     <ol>
      <li data-md>
       <p>An <i>awaitable</i> is an expression that would be well-formed as the operand of a <code class="highlight"><c- k>co_await</c-></code> expression within a coroutine that does not define an <code class="highlight"><c- n>await_transform</c-></code> member in its promise type.</p>
      <li data-md>
       <p>For any type <code class="highlight"><c- n>T</c-></code>, <code class="highlight"><i><c- n>is</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> is <code class="highlight">true</code> if an expression of that type is an awaitable as described above; otherwise, <code class="highlight">false</code>.</p>
      <li data-md>
       <p>For an awaitable <code class="highlight"><c- n>a</c-></code> such that <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>a</c-><c- p>))</c-></code> is type <code class="highlight"><c- n>A</c-></code>, <code class="highlight"><i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>A</c-><c- o>></c-></code> is an alias for <code class="highlight"><c- k>decltype</c-><c- p>(</c-><i><c- n>e</c-></i><c- p>)</c-></code>, where <code class="highlight"><i><c- n>e</c-></i></code> is <code class="highlight"><c- n>a</c-></code>'s <i>await-resume</i> expression ([expr.await]).</p>
     </ol>
    <li data-md>
     <p>The primary class template <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is defined as if inheriting from an implementation-defined class template <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> defined as follows:</p>
     <ol>
      <li data-md>
       <p>If <code class="highlight"><i><c- n>has</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>types</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight">true</code>, then <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is equivalent to:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- k>typename</c-> <c- nc>S</c-><c- o>::</c-><c- k>template</c-> <c- n>value_types</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- p>,</c-> <c- n>Variant</c-><c- o>></c-><c- p>;</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- k>typename</c-> <c- nc>S</c-><c- o>::</c-><c- k>template</c-> <c- n>error_types</c-><c- o>&lt;</c-><c- n>Variant</c-><c- o>></c-><c- p>;</c->

    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>sends_done</c-> <c- o>=</c-> <c- n>S</c-><c- o>::</c-><c- n>sends_done</c-><c- p>;</c->
  <c- p>};</c->
</pre>
      <li data-md>
       <p>Otherwise, if <code class="highlight"><c- n>derived_from</c-><c- o>&lt;</c-><c- n>S</c-><c- p>,</c-> <c- n>sender_base</c-><c- o>></c-></code> is <code class="highlight">true</code>, then <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></i></code> is equivalent to</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i> <c- p>{};</c->
</pre>
      <li data-md>
       <p>Otherwise, if <code class="highlight"><i><c- n>is</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight">true</code>, then</p>
       <ol>
        <li data-md>
         <p>If <code class="highlight"><i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight"><i><c- n>cv</c-></i> <c- b>void</c-></code> then <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></i></code> is equivalent to</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;>></c-><c- p>;</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>exception_ptr</c-><c- o>></c-><c- p>;</c->

    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>sends_done</c-> <c- o>=</c-> false<c- p>;</c->
  <c- p>};</c->
</pre>
        <li data-md>
         <p>Otherwise, <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></i></code> is equivalent to</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;</c-><i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-><c- p>;</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
      <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>exception_ptr</c-><c- o>></c-><c- p>;</c->

    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>sends_done</c-> <c- o>=</c-> false<c- p>;</c->
  <c- p>};</c->
</pre>
       </ol>
      <li data-md>
       <p>Otherwise, <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is equivalent to</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>struct</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>traits</c-><c- o>-</c-><c- n>base</c-></i> <c- p>{</c->
    <c- k>using</c-> <c- n>__unspecialized</c-> <c- o>=</c-> <c- b>void</c-><c- p>;</c-> <c- c1>// exposition only</c->
  <c- p>};</c->
</pre>
     </ol>
    <li data-md>
     <p>If <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>::</c-><c- n>value_types</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- p>,</c-> <c- n>Variant</c-><c- o>></c-></code> for some sender type <code class="highlight"><c- n>S</c-></code> is well formed, it shall be a type <code class="highlight"><c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;</c-><c- n>Args</c-><sub><c- n>0</c-></sub><c- p>...</c-><c- o>></c-><c- p>,</c-> <c- n>Tuple</c-><c- o>&lt;</c-><c- n>Args</c-><sub><c- n>1</c-></sub><c- p>...</c-><c- o>></c-><c- p>,</c-> <c- p>...,</c-> <c- n>Tuple</c-><c- o>&lt;</c-><c- n>Args</c-><sub><c- n>N</c-></sub><c- p>...</c-><c- o>>>></c-></code>, where the type packs <code class="highlight"><c- n>Args</c-><sub><c- n>0</c-></sub></code> through <code class="highlight"><c- n>Args</c-><sub><c- n>N</c-></sub></code> are the packs of types the sender <code class="highlight"><c- n>S</c-></code> passes as
arguments to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> after a receiver object. If such sender <code class="highlight"><c- n>S</c-></code> invokes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> for some receiver <code class="highlight"><c- n>r</c-></code>, where <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- n>args</c-><c- p>)</c-></code> is not one of the type packs <code class="highlight"><c- n>Args</c-><sub><c- n>0</c-></sub></code> through <code class="highlight"><c- n>Args</c-><sub><c- n>N</c-></sub></code>, the program is ill-formed with no
diagnostic required.</p>
    <li data-md>
     <p>If <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>::</c-><c- n>error_types</c-><c- o>&lt;</c-><c- n>Variant</c-><c- o>></c-></code> for some sender type <code class="highlight"><c- n>S</c-></code> is well formed, it shall be a type <code class="highlight"><c- n>Variant</c-><c- o>&lt;</c-><c- n>E</c-><sub><c- n>0</c-></sub><c- p>,</c-> <c- n>E</c-><sub><c- n>1</c-></sub><c- p>,</c-> <c- p>...,</c-> <c- n>E</c-><sub><c- n>N</c-></sub><c- o>></c-></code>, where the types <code class="highlight"><c- n>E</c-><sub><c- n>0</c-></sub></code> through <code class="highlight"><c- n>E</c-><sub><c- n>N</c-></sub></code> are the types the sender <code class="highlight"><c- n>S</c-></code> passes as arguments to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> after a receiver
object. If such sender <code class="highlight"><c- n>S</c-></code> invokes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> for some receiver <code class="highlight"><c- n>r</c-></code>, where <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- n>e</c-><c- p>)</c-></code> is not one of the types <code class="highlight"><c- n>E</c-><sub><c- n>0</c-></sub></code> through <code class="highlight"><c- n>E</c-><sub><c- n>N</c-></sub></code>, the program is ill-formed with no diagnostic required.</p>
    <li data-md>
     <p>If <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>::</c-><c- n>sends_done</c-></code> is well formed and <code class="highlight">false</code>, and such sender <code class="highlight"><c- n>S</c-></code> invokes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> for some receiver <code class="highlight"><c- n>r</c-></code>, the program is ill-formed with no diagnostic required.</p>
    <li data-md>
     <p>Users may specialize <code class="highlight"><c- n>sender_traits</c-></code> on program-defined types.</p>
   </ol>
   <h4 class="heading settled" data-level="9.6.2" id="spec-execution.senders.connect"><span class="secno">9.6.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> <b>[execution.senders.connect]</b></span><a class="self-link" href="#spec-execution.senders.connect"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> is used to <i>connect</i> a sender with a receiver, producing an operation state object that represents the work that needs to be performed to satisfy the receiver contract of the receiver with values that are the result of the operations
described by the sender.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>r</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code> and <code class="highlight"><c- n>R</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>r</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>R</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>receiver</c-></code> or <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>operation_state</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return an operation state for which <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> starts work described by <code class="highlight"><c- n>s</c-></code>, the program
is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code> if <code class="highlight"><i><c- n>is</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight">true</code> and that expression is valid, where <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> is a coroutine equivalent to the following:</p>
<pre class="highlight"><i><c- n>operation</c-><c- o>-</c-><c- n>state</c-><c- o>-</c-><c- n>task</c-></i> <i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i><c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>R</c-><c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- k>requires</c-> <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- p>{</c->
  <c- n>exception_ptr</c-> <c- n>e</c-><c- p>;</c->
  <c- k>try</c-> <c- p>{</c->
    <i><c- n>set</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>expr</c-></i>
  <c- p>}</c-> <c- k>catch</c-><c- p>(...)</c-> <c- p>{</c->
    <c- n>e</c-> <c- o>=</c-> <c- n>current_exception</c-><c- p>();</c->
  <c- p>}</c->
  <i><c- n>set</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>expr</c-></i>
<c- p>}</c->
</pre>
       <p>where <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> suspends at the <i>initial suspends point</i> ([dcl.fct.def.coroutine]), and:</p>
       <ol>
        <li data-md>
         <p><i>set-value-expr</i> first evaluates <code class="highlight"><c- k>co_await</c-> <c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-></code>, then suspends the coroutine and evaluates <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>)</c-></code> if <code class="highlight"><i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight"><i><c- n>cv</c-></i> <c- b>void</c-></code>; otherwise, it evaluates <code class="highlight"><c- k>auto</c-><c- o>&amp;&amp;</c-> <c- n>res</c-> <c- o>=</c-> <c- k>co_await</c-> <c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-></code>, then suspends the coroutine and evaluates <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>,</c-> <c- p>(</c-><c- k>decltype</c-><c- p>(</c-><c- n>res</c-><c- p>))</c-> <c- n>res</c-><c- p>)</c-></code>.</p>
         <p>If the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> exits with an exception, the coroutine is resumed and the exception is immediately propagated in the context of the coroutine.</p>
         <p>[<i>Note</i>: If the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> exits normally, then the <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> coroutine is never resumed. --<i>end note</i>]</p>
        <li data-md>
         <p><i>set-error-expr</i> first suspends the coroutine and then executes <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>e</c-><c- p>))</c-></code>.</p>
         <p>[<i>Note</i>: The <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> coroutine is never resumed after the call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code>. --<i>end note</i>]</p>
        <li data-md>
         <p><code class="highlight"><i><c- n>operation</c-><c- o>-</c-><c- n>state</c-><c- o>-</c-><c- n>task</c-></i></code> is a type that models <code class="highlight"><c- n>operation_state</c-></code>. Its <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> resumes the <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> coroutine, advancing it past the initial suspend point.</p>
        <li data-md>
         <p>Let <code class="highlight"><c- n>p</c-></code> be an lvalue reference to the promise of the <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> coroutine, let <code class="highlight"><c- n>b</c-></code> be a <code class="highlight"><c- k>const</c-></code> lvalue reference to the receiver <code class="highlight"><c- n>r</c-></code>, and let <code class="highlight"><c- n>c</c-></code> be any customization point object excluding those of type <code class="highlight"><c- n>set_value_t</c-></code>, <code class="highlight"><c- n>set_error_t</c-></code> and <code class="highlight"><c- n>set_done_t</c-></code>. Then <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tag_invoke</c-><c- p>(</c-><c- n>c</c-><c- p>,</c-> <c- n>p</c-><c- p>,</c-> <c- n>as</c-><c- p>...)</c-></code> is expression-equivalent to <code class="highlight"><c- n>c</c-><c- p>(</c-><c- n>b</c-><c- p>,</c-> <c- n>as</c-><c- p>...)</c-></code> for any set of arguments <code class="highlight"><c- n>as</c-><c- p>...</c-></code>.</p>
        <li data-md>
         <p>The expression <code class="highlight"><c- n>p</c-><c- p>.</c-><c- n>unhandled_done</c-><c- p>()</c-></code> is expression-equivalent to <code class="highlight"><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>((</c-><c- n>R</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>r</c-><c- p>),</c-> <c- n>noop_coroutine</c-><c- p>())</c-></code>.</p>
       </ol>
       <p>The operand of the <i>requires-clause</i> of <code class="highlight"><i><c- n>connect</c-><c- o>-</c-><c- n>awaitable</c-></i></code> is equivalent to <code class="highlight"><c- n>receiver_of</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-></code> if <code class="highlight"><i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is <code class="highlight"><i><c- n>cv</c-></i> <c- b>void</c-></code>; otherwise, it is <code class="highlight"><c- n>receiver_of</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <i><c- n>await</c-><c- o>-</c-><c- n>result</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
    <li data-md>
     <p>Standard sender types shall always expose an rvalue-qualified overload of a customization of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>. Standard sender types shall only expose an lvalue-qualified overload of a customization of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code> if they are copyable.</p>
   </ol>
   <h4 class="heading settled" data-level="9.6.3" id="spec-execution.senders.queries"><span class="secno">9.6.3. </span><span class="content">Sender queries <b>[execution.senders.queries]</b></span><a class="self-link" href="#spec-execution.senders.queries"></a></h4>
   <h5 class="heading settled" data-level="9.6.3.1" id="spec-execution.senders.queries.get_completion_scheduler"><span class="secno">9.6.3.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code> <b>[execution.senders.queries.get_completion_scheduler]</b></span><a class="self-link" href="#spec-execution.senders.queries.get_completion_scheduler"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code> is used to ask a sender object for the <i>completion scheduler</i> for one of its signals.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-></code> denotes a customization point object template. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is ill-formed for all template arguments <code class="highlight"><c- n>CPO</c-></code>. If the template
argument <code class="highlight"><c- n>CPO</c-></code> in <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code> is not one of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error_t</c-></code>, or <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done_t</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-><c- p>,</c-> <c- n>as_const</c-><c- p>(</c-><c- n>s</c-><c- p>))</c-></code>, if this expression is well formed and satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, and is <code class="highlight"><c- k>noexcept</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
    <li data-md>
     <p>If, for some sender <code class="highlight"><c- n>s</c-></code> and customization point object <code class="highlight"><c- n>CPO</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>CPO</c-><c- p>)</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is well-formed and results in a scheduler <code class="highlight"><c- n>sch</c-></code>, and the sender <code class="highlight"><c- n>s</c-></code> invokes <code class="highlight"><c- n>CPO</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>, for some receiver <code class="highlight"><c- n>r</c-></code> which has been connected to <code class="highlight"><c- n>s</c-></code>, with additional arguments <code class="highlight"><c- n>args</c-><c- p>...</c-></code>, on an execution agent which does not belong to the associated execution context of <code class="highlight"><c- n>sch</c-></code>, the behavior is undefined.</p>
   </ol>
   <h4 class="heading settled" data-level="9.6.4" id="spec-execution.senders.factories"><span class="secno">9.6.4. </span><span class="content">Sender factories <b>[execution.senders.factories]</b></span><a class="self-link" href="#spec-execution.senders.factories"></a></h4>
   <h5 class="heading settled" data-level="9.6.4.1" id="spec-execution.senders.factories.general"><span class="secno">9.6.4.1. </span><span class="content">General <b>[execution.senders.factories.general]</b></span><a class="self-link" href="#spec-execution.senders.factories.general"></a></h5>
   <ol>
    <li data-md>
     <p>Subclause [execution.senders.factories] defines <i>sender factories</i>, which are utilities that return senders without accepting senders as arguments.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.4.2" id="spec-execution.senders.schedule"><span class="secno">9.6.4.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> <b>[execution.senders.schedule]</b></span><a class="self-link" href="#spec-execution.senders.schedule"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> is used to obtain a sender associated with a scheduler, which can be used to describe work to be started on that scheduler’s associated execution context.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender whose <code class="highlight"><c- n>set_value</c-></code> completion scheduler is equivalent to <code class="highlight"><c- n>s</c-></code>, the program is ill-formed with no
diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is ill-formed.</p>
     </ol>
   </ol>
   <h5 class="heading settled" data-level="9.6.4.3" id="spec-execution.senders.just"><span class="secno">9.6.4.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just</c-></code> <b>[execution.senders.just]</b></span><a class="self-link" href="#spec-execution.senders.just"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just</c-></code> is used to create a sender that propagates a set of values to a connected receiver.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
<c- k>struct</c-> <i><c- nc>just</c-><c- o>-</c-><c- n>sender</c-></i> <c- c1>// exposition only</c->
<c- p>{</c->
  <c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- n>Ts</c-><c- p>...</c-><c- o>></c-> <c- n>vs_</c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;</c-><c- n>Ts</c-><c- p>...</c-><c- o>>></c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>exception_ptr</c-><c- o>></c-><c- p>;</c->

  <c- k>static</c-> <c- k>const</c-> <c- k>constexpr</c-> <c- k>auto</c-> <c- n>sends_done</c-> <c- o>=</c-> false<c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>R</c-><c- o>></c->
  <c- k>struct</c-> <c- nc>operation_state</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- n>Ts</c-><c- p>...</c-><c- o>></c-> <c- n>vs_</c-><c- p>;</c->
    <c- n>R</c-> <c- n>r_</c-><c- p>;</c->

    <c- k>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start_t</c-><c- p>,</c-> <c- n>operation_state</c-><c- o>&amp;</c-> <c- n>s</c-><c- p>)</c->
      <c- k>noexcept</c-> <c- p>{</c->
      <c- k>try</c-> <c- p>{</c->
        <c- n>apply</c-><c- p>([</c-><c- o>&amp;</c-><c- n>s</c-><c- p>](</c-><c- n>Ts</c-> <c- o>&amp;</c-><c- p>...</c-> <c- n>values_</c-><c- p>)</c-> <c- p>{</c->
          <c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>s</c-><c- p>.</c-><c- n>r_</c-><c- p>),</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>values_</c-><c- p>)...);</c->
        <c- p>},</c-> <c- n>s</c-><c- p>.</c-><c- n>vs_</c-><c- p>);</c->
      <c- p>}</c->
      <c- k>catch</c-> <c- p>(...)</c-> <c- p>{</c->
        <c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>s</c-><c- p>.</c-><c- n>r_</c-><c- p>),</c-> <c- n>current_exception</c-><c- p>());</c->
      <c- p>}</c->
    <c- p>}</c->
  <c- p>};</c->

  <c- k>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- k>requires</c-> <c- n>receiver_of</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>Ts</c-><c- p>...</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- p>(</c-><c- n>copyable</c-><c- o>&lt;</c-><c- n>Ts</c-><c- o>></c-> <c- o>&amp;&amp;</c-><c- p>...)</c->
  <c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- k>const</c-> <i><c- n>just</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&amp;</c-> <c- n>j</c-><c- p>,</c-> <c- n>R</c-> <c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>operation_state</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>{</c-> <c- n>j</c-><c- p>.</c-><c- n>vs_</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>(</c-><c- n>r</c-><c- p>)</c-> <c- p>};</c->
  <c- p>}</c->

  <c- k>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- k>requires</c-> <c- n>receiver_of</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>Ts</c-><c- p>...</c-><c- o>></c->
  <c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <i><c- n>just</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&amp;&amp;</c-> <c- n>j</c-><c- p>,</c-> <c- n>R</c-> <c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>operation_state</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>j</c-><c- p>.</c-><c- n>vs_</c-><c- p>),</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>(</c-><c- n>r</c-><c- p>)</c-> <c- p>};</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><i><c- n>moveable</c-><c- o>-</c-><c- n>value</c-></i><c- p>...</c-> <c- n>Ts</c-><c- o>></c->
  <i><c- n>just</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>Ts</c-><c- o>></c-><c- p>...</c-><c- o>></c-> <c- n>just</c-><c- p>(</c-><c- n>Ts</c-> <c- o>&amp;&amp;</c-><c- p>...</c-> <c- n>ts</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>(</c-><i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>);</c->
</pre>
    <li data-md>
     <p><i>Effects</i>: Initializes <code class="highlight"><c- n>vs_</c-></code> with <code class="highlight"><c- n>make_tuple</c-><c- p>(</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Ts</c-><c- o>></c-><c- p>(</c-><c- n>ts</c-><c- p>)...)</c-></code>.</p>
    <li data-md>
     <p><i>Remarks</i>: The expression in the <code class="highlight"><c- k>noexcept</c-><c- o>-</c-><c- n>specifier</c-></code> is equivalent to</p>
<pre class="highlight"><c- p>(</c-><c- n>is_nothrow_constructible_v</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>Ts</c-><c- o>></c-><c- p>,</c-> <c- n>Ts</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- p>...)</c->
</pre>
   </ol>
   <h5 class="heading settled" data-level="9.6.4.4" id="spec-execution.senders.transfer_just"><span class="secno">9.6.4.4. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code> <b>[execution.senders.transfer_just]</b></span><a class="self-link" href="#spec-execution.senders.transfer_just"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code> is used to create a sender that propagates a set of values to a connected receiver on an execution agent belonging to the associated execution context of a specified scheduler.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>vs</c-><c- p>...</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code> and <code class="highlight"><c- n>Vs</c-><c- p>...</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>vs</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, or any type <code class="highlight"><c- n>V</c-></code> in <code class="highlight"><c- n>Vs</c-></code> does not
satisfy <code class="highlight"><i><c- n>moveable</c-><c- o>-</c-><c- n>value</c-></i></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>vs</c-><c- p>...)</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>vs</c-><c- p>...)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>transfer_just</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>vs</c-><c- p>...)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender whose <code class="highlight"><c- n>set_value</c-></code> completion scheduler is equivalent to <code class="highlight"><c- n>s</c-></code> and sends
values equivalent to <code class="highlight"><c- n>vs</c-><c- p>...</c-></code> to a receiver connected to it, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- n>vs</c-><c- p>...),</c-> <c- n>s</c-><c- p>)</c-></code>.</p>
     </ol>
   </ol>
   <h5 class="heading settled" data-level="9.6.4.5" id="spec-execution.senders.just_error"><span class="secno">9.6.4.5. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code> <b>[execution.senders.just_error]</b></span><a class="self-link" href="#spec-execution.senders.just_error"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_error</c-></code> is used to create a sender that propagates an error to a connected receiver.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
<c- k>struct</c-> <i><c- nc>just</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>sender</c-></i> <c- c1>// exposition only</c->
<c- p>{</c->
  <c- n>T</c-> <c- n>err_</c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;></c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>exception_ptr</c-><c- o>></c-><c- p>;</c->

  <c- k>static</c-> <c- k>const</c-> <c- k>constexpr</c-> <c- k>auto</c-> <c- n>sends_done</c-> <c- o>=</c-> false<c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>R</c-><c- o>></c->
  <c- k>struct</c-> <c- nc>operation_state</c-> <c- p>{</c->
    <c- n>T</c-> <c- n>err_</c-><c- p>;</c->
    <c- n>R</c-> <c- n>r_</c-><c- p>;</c->

    <c- k>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start_t</c-><c- p>,</c-> <c- n>operation_state</c-><c- o>&amp;</c-> <c- n>s</c-><c- p>)</c->
      <c- k>noexcept</c-> <c- p>{</c->
      <c- k>try</c-> <c- p>{</c->
        <c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>s</c-><c- p>.</c-><c- n>r_</c-><c- p>),</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>err_</c-><c- p>));</c->
      <c- p>}</c->
      <c- k>catch</c-> <c- p>(...)</c-> <c- p>{</c->
        <c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>s</c-><c- p>.</c-><c- n>r_</c-><c- p>),</c-> <c- n>current_exception</c-><c- p>());</c->
      <c- p>}</c->
    <c- p>}</c->
  <c- p>};</c->

  <c- k>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- k>requires</c-> <c- n>receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>copyable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->
  <c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- k>const</c-> <i><c- n>just</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&amp;</c-> <c- n>j</c-><c- p>,</c-> <c- n>R</c-> <c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>operation_state</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>R</c-><c- o>>></c-><c- p>{</c-> <c- n>j</c-><c- p>.</c-><c- n>err_</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>(</c-><c- n>r</c-><c- p>)</c-> <c- p>};</c->
  <c- p>}</c->

  <c- k>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
    <c- k>requires</c-> <c- n>receiver</c-><c- o>&lt;</c-><c- n>R</c-><c- p>,</c-> <c- n>T</c-><c- o>></c->
  <c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <i><c- n>just</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&amp;&amp;</c-> <c- n>j</c-><c- p>,</c-> <c- n>R</c-> <c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>operation_state</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>R</c-><c- o>>></c-><c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>j</c-><c- p>.</c-><c- n>err_</c-><c- p>),</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>(</c-><c- n>r</c-><c- p>)</c-> <c- p>};</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><i><c- n>moveable</c-><c- o>-</c-><c- n>value</c-></i> <c- n>T</c-><c- o>></c->
  <i><c- n>just</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-> <c- n>just_error</c-><c- p>(</c-><c- n>T</c-> <c- o>&amp;&amp;</c-> <c- n>t</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>(</c-><i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i><c- p>);</c->
</pre>
    <li data-md>
     <p><i>Effects</i>: Returns a <code class="highlight"><i><c- n>just</c-><c- o>-</c-><c- n>error</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code> with <code class="highlight"><c- n>err_</c-></code> direct initialized with <code class="highlight"><c- k>static_cast</c-><c- o>&lt;</c-><c- n>T</c-><c- o>&amp;&amp;></c-><c- p>(</c-><c- n>t</c-><c- p>)</c-></code>.</p>
    <li data-md>
     <p><i>Remarks</i>: The expression in the <code class="highlight"><c- k>noexcept</c-><c- o>-</c-><c- n>specifier</c-></code> is equivalent to</p>
<pre class="highlight"><c- n>is_nothrow_constructible_v</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>,</c-> <c- n>T</c-><c- o>></c->
</pre>
   </ol>
   <h5 class="heading settled" data-level="9.6.4.6" id="spec-execution.senders.just_done"><span class="secno">9.6.4.6. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code> <b>[execution.senders.just_done]</b></span><a class="self-link" href="#spec-execution.senders.just_done"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>just_done</c-></code> is used to create a sender that propagates a done signal to a connected receiver.</p>
<pre class="highlight"><c- k>struct</c-> <i><c- nc>just</c-><c- o>-</c-><c- n>done</c-><c- o>-</c-><c- n>sender</c-></i> <c- c1>// exposition only</c->
<c- p>{</c->
  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Tuple</c-><c- p>,</c-> <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>value_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;></c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-><c- p>...</c-><c- o>></c-> <c- k>class</c-> <c- nc>Variant</c-><c- o>></c->
  <c- k>using</c-> <c- n>error_types</c-> <c- o>=</c-> <c- n>Variant</c-><c- o>&lt;></c-><c- p>;</c->

  <c- k>static</c-> <c- k>const</c-> <c- k>constexpr</c-> <c- k>auto</c-> <c- n>sends_done</c-> <c- o>=</c-> true<c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>R</c-><c- o>></c->
  <c- k>struct</c-> <c- nc>operation_state</c-> <c- p>{</c->
    <c- n>R</c-> <c- n>r_</c-><c- p>;</c->

    <c- k>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start_t</c-><c- p>,</c-> <c- n>operation_state</c-><c- o>&amp;</c-> <c- n>s</c-><c- p>)</c->
      <c- k>noexcept</c-> <c- p>{</c->
      <c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>s</c-><c- p>.</c-><c- n>r_</c-><c- p>));</c->
    <c- p>}</c->
  <c- p>};</c->

  <c- k>template</c-><c- o>&lt;</c-><c- n>receiver</c-> <c- n>R</c-><c- o>></c->
  <c- k>friend</c-> <c- k>auto</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>connect_t</c-><c- p>,</c-> <c- k>const</c-> <i><c- n>just</c-><c- o>-</c-><c- n>done</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&amp;</c-> <c- n>j</c-><c- p>,</c-> <c- n>R</c-> <c- o>&amp;&amp;</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>operation_state</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>{</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>R</c-><c- o>></c-><c- p>(</c-><c- n>r</c-><c- p>)</c-> <c- p>};</c->
  <c- p>}</c->
<c- p>};</c->

<i><c- n>just</c-><c- o>-</c-><c- n>done</c-><c- o>-</c-><c- n>sender</c-></i> <c- n>just_done</c-><c- p>()</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
    <li data-md>
     <p><i>Effects</i>: Equivalent to <code class="highlight"><i><c- n>just</c-><c- o>-</c-><c- n>done</c-><c- o>-</c-><c- n>sender</c-></i><c- p>{}</c-></code>.</p>
   </ol>
   <h4 class="heading settled" data-level="9.6.5" id="spec-execution.senders.adaptors"><span class="secno">9.6.5. </span><span class="content">Sender adaptors <b>[execution.senders.adaptors]</b></span><a class="self-link" href="#spec-execution.senders.adaptors"></a></h4>
   <h5 class="heading settled" data-level="9.6.5.1" id="spec-execution.senders.adaptors.general"><span class="secno">9.6.5.1. </span><span class="content">General <b>[execution.senders.adaptors.general]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.general"></a></h5>
   <ol>
    <li data-md>
     <p>Subclause [execution.senders.adaptors] defines <i>sender adaptors</i>, which are utilities that transform one or more senders into a sender with custom behaviors. When they accept a single sender argument, they can be chained to create sender chains.</p>
    <li data-md>
     <p>The bitwise OR operator is overloaded for the purpose of creating sender chains. The adaptors also support function call syntax with equivalent semantics.</p>
    <li data-md>
     <p>Unless otherwise specified, a sender adaptor is required to not begin executing any functions which would observe or modify any of the arguments of the adaptor before the returned sender is connected with a receiver using <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>, and <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> is called on the resulting operation state. This requirement applies to any function that is selected by the implementation of the sender adaptor.</p>
    <li data-md>
     <p>Unless otherwise specified, all sender adaptors which accept a single <code class="highlight"><c- n>sender</c-></code> argument return sender objects that propagate sender queries to that single sender argument. This requirement applies to any function that is selected by the implementation of the
sender adaptor.</p>
    <li data-md>
     <p>Unless otherwise specified, whenever a sender adaptor constructs a receiver it passes to another sender’s connect, that receiver shall propagate receiver queries to a receiver accepted as an argument of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-></code>. This requirements
applies to any sender returned from a function that is selected by the implementation of such sender adaptor.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.2" id="spec-execution.senders.adaptor.objects"><span class="secno">9.6.5.2. </span><span class="content">Sender adaptor closure objects <b>[execution.senders.adaptor.objects]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.objects"></a></h5>
   <ol>
    <li data-md>
     <p>A <i>pipeable sender adaptor closure object</i> is a function object that accepts one or more <code class="highlight"><c- n>sender</c-></code> arguments and returns a <code class="highlight"><c- n>sender</c-></code>. For a sender adaptor closure object <code class="highlight"><c- n>C</c-></code> and an expression <code class="highlight"><c- n>S</c-></code> such that <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>S</c-><c- p>))</c-></code> models <code class="highlight"><c- n>sender</c-></code>, the following
expressions are equivalent and yield a <code class="highlight"><c- n>sender</c-></code>:</p>
<pre class="highlight"><c- n>C</c-><c- p>(</c-><c- n>S</c-><c- p>)</c->
<c- n>S</c-> <c- o>|</c-> <c- n>C</c->
</pre>
     <p>Given an additional pipeable sender adaptor closure object <code class="highlight"><c- n>D</c-></code>, the expression <code class="highlight"><c- n>C</c-> <c- o>|</c-> <c- n>D</c-></code> produces another pipeable sender adaptor closure object <code class="highlight"><c- n>E</c-></code>:</p>
     <p><code class="highlight"><c- n>E</c-></code> is a perfect forwarding call wrapper ([func.require]) with the following properties:</p>
     <ul>
      <li data-md>
       <p>Its target object is an object <code class="highlight"><c- n>d</c-></code> of type <code class="highlight"><c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>((</c-><c- n>D</c-><c- p>))</c-><c- o>></c-></code> direct-non-list-initialized with <code class="highlight"><c- n>D</c-></code>.</p>
      <li data-md>
       <p>It has one bound argument entity, an object <code class="highlight"><c- n>c</c-></code> of type <code class="highlight"><c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>((</c-><c- n>C</c-><c- p>))</c-><c- o>></c-></code> direct-non-list-initialized with <code class="highlight"><c- n>C</c-></code>.</p>
      <li data-md>
       <p>Its call pattern is <code class="highlight"><c- n>d</c-><c- p>(</c-><c- n>c</c-><c- p>(</c-><c- n>arg</c-><c- p>))</c-></code>, where <code class="highlight"><c- n>arg</c-></code> is the argument used in a function call expression of <code class="highlight"><c- n>E</c-></code>.</p>
     </ul>
     <p>The expression <code class="highlight"><c- n>C</c-> <c- o>|</c-> <c- n>D</c-></code> is well-formed if and only if the initializations of the state entities of <code class="highlight"><c- n>E</c-></code> are all well-formed.</p>
    <li data-md>
     <p>An object <code class="highlight"><c- n>t</c-></code> of type <code class="highlight"><c- n>T</c-></code> is a pipeable sender adaptor closure object if <code class="highlight"><c- n>T</c-></code> models <code class="highlight"><c- n>derived_from</c-><c- o>&lt;</c-><c- n>sender_adaptor_closure</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code>, <code class="highlight"><c- n>T</c-></code> has no other base
classes of type <code class="highlight"><c- n>range_adaptor_closure</c-><c- o>&lt;</c-><c- n>U</c-><c- o>></c-></code> for any other type <code class="highlight"><c- n>U</c-></code>, and <code class="highlight"><c- n>T</c-></code> does not model <code class="highlight"><c- n>sender</c-></code>.</p>
    <li data-md>
     <p>The template parameter <code class="highlight"><c- n>D</c-></code> for <code class="highlight"><c- n>sender_adaptor_closure</c-></code> may be an incomplete type. Before any expression of type <code class="highlight"><i><c- n>cv</c-></i> <c- n>D</c-></code> appears as
an operand to the <code class="highlight"><c- o>|</c-></code> operator, <code class="highlight"><c- n>D</c-></code> shall be complete and model <code class="highlight"><c- n>derived_from</c-><c- o>&lt;</c-><c- n>range_adaptor_closure</c-><c- o>&lt;</c-><c- n>D</c-><c- o>>></c-></code>. The behavior of an expression involving an
object of type <code class="highlight"><i><c- n>cv</c-></i> <c- n>D</c-></code> as an operand to the <code class="highlight"><c- o>|</c-></code> operator is undefined if overload resolution selects a program-defined <code class="highlight"><c- k>operator</c-><c- o>|</c-></code> function.</p>
    <li data-md>
     <p>A <i>pipeable sender adaptor object</i> is a customization point object that accepts a <code class="highlight"><c- n>sender</c-></code> as its first argument and returns a <code class="highlight"><c- n>sender</c-></code>.</p>
    <li data-md>
     <p>If a pipeable sender adaptor object accepts only one argument, then it is a pipeable sender adaptor closure object.</p>
    <li data-md>
     <p>If a pipeable sender adaptor object <code class="highlight"><c- n>adaptor</c-></code> accepts more than one argument, then let <code class="highlight"><c- n>s</c-></code> be an expression such that <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code> models <code class="highlight"><c- n>sender</c-></code>,
let <code class="highlight"><c- n>args</c-><c- p>...</c-></code> be arguments such that <code class="highlight"><c- n>adaptor</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is a well-formed expression as specified in the rest of this subclause
([execution.senders.adaptor.objects]), and let <code class="highlight"><c- n>BoundArgs</c-></code> be a pack that denotes <code class="highlight"><c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>((</c-><c- n>args</c-><c- p>))</c-><c- o>></c-><c- p>...</c-></code>. The expression <code class="highlight"><c- n>adaptor</c-><c- p>(</c-><c- n>args</c-><c- p>...)</c-></code> produces a pipeable sender adaptor closure object <code class="highlight"><c- n>f</c-></code> that is a perfect forwarding call wrapper with the following properties:</p>
     <ul>
      <li data-md>
       <p>Its target object is a copy of <code class="highlight"><c- n>adaptor</c-></code>.</p>
      <li data-md>
       <p>Its bound argument entities <code class="highlight"><c- n>bound_args</c-></code> consist of objects of types <code class="highlight"><c- n>BoundArgs</c-><c- p>...</c-></code> direct-non-list-initialized with <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>((</c-><c- n>args</c-><c- p>))</c-><c- o>></c-><c- p>(</c-><c- n>args</c-><c- p>)...</c-></code>, respectively.</p>
      <li data-md>
       <p>Its call pattern is <code class="highlight"><c- n>adaptor</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>bound_args</c-><c- p>...)</c-></code>, where <code class="highlight"><c- n>r</c-></code> is the argument used in a function call expression of <code class="highlight"><c- n>f</c-></code>.</p>
     </ul>
   </ol>
   <p>The expression <code class="highlight"><c- n>adaptor</c-><c- p>(</c-><c- n>args</c-><c- p>...)</c-></code> is well-formed if and only if the initializations of the bound argument entities of the result, as specified above,
are all well-formed.</p>
   <h5 class="heading settled" data-level="9.6.5.3" id="spec-execution.senders.adaptors.on"><span class="secno">9.6.5.3. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code> <b>[execution.senders.adaptors.on]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.on"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code> is used to adapt a sender in a sender that will start the input sender on an execution agent belonging to a specific execution context.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>sch</c-></code> and <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>Sch</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>sch</c-><c- p>))</c-></code> and <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>Sch</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, or <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>on</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>on</c-><c- p>,</c-> <c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected above does not return a sender which starts <code class="highlight"><c- n>s</c-></code> on an execution agent of the associated execution context of <code class="highlight"><c- n>sch</c-></code> when
started, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it results in an operation state <code class="highlight"><c- n>op_state</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-></code> is called on <code class="highlight"><c- n>op_state</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol start="2">
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>out_r</c-><c- p>)</c-></code>, which results in <code class="highlight"><c- n>op_state2</c-></code>. It calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>. If any of these throws an exception, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-></code> on <code class="highlight"><c- n>out_r</c-></code>,
passing <code class="highlight"><c- n>current_exception</c-><c- p>()</c-></code> as the second argument.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>)</c-></code>, which results in <code class="highlight"><c- n>s3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s3</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in <code class="highlight"><c- n>op_state3</c-></code>, and then it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state3</c-><c- p>)</c-></code>.</p>
        <li data-md>
         <p>The lifetimes of <code class="highlight"><c- n>op_state2</c-></code> and <code class="highlight"><c- n>op_state3</c-></code>, once constructed, last until <code class="highlight"><c- n>op_state</c-></code> is destroyed.</p>
       </ol>
     </ol>
    <li data-md>
     <p>Any receiver <code class="highlight"><c- n>r</c-></code> created by an implementation of <code class="highlight"><c- n>on</c-></code> shall implement the <code class="highlight"><c- n>get_scheduler</c-></code> receiver query. The scheduler returned from the query for all such receivers should be equivalent to the <code class="highlight"><c- n>sch</c-></code> argument passed into the <code class="highlight"><c- n>on</c-></code> call.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.4" id="spec-execution.senders.adaptors.transfer"><span class="secno">9.6.5.4. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> <b>[execution.senders.adaptors.transfer]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.transfer"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> is used to adapt a sender into a sender with a different associated <code class="highlight"><c- n>set_value</c-></code> completion scheduler. [<i>Note</i>: it results in a transition between different execution contexts when executed. --<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>sch</c-></code> and <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>Sch</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>sch</c-><c- p>))</c-></code> and <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>Sch</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, or <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>sch</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>sch</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>sch</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>schedule_from</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>.</p>
     </ol>
     <p>If the function selected above does not return a sender which is a result of a call to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>s2</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>s2</c-></code> is a sender which sends equivalent to those sent by <code class="highlight"><c- n>s</c-></code>, the program is ill-formed with no diagnostic required.</p>
    <li data-md>
     <p>Senders returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> shall not propagate the sender queries <code class="highlight"><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code> to an input sender. They shall return a scheduler equivalent to the <code class="highlight"><c- n>sch</c-></code> argument from those queries.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.5" id="spec-execution.senders.adaptors.schedule_from"><span class="secno">9.6.5.5. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-></code> <b>[execution.senders.adaptors.schedule_from]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.schedule_from"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-></code> is used to schedule work dependent on the completion of a sender onto a scheduler’s associated execution context. [<i>Note</i>: <code class="highlight"><c- n>schedule_from</c-></code> is not meant to be used in user code; they are used in the implementation of <code class="highlight"><c- n>transfer</c-></code>. -<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>sch</c-></code> and <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>Sch</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>sch</c-><c- p>))</c-></code> and <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>Sch</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code>, or <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>schedule_from</c-><c- p>,</c-> <c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender which completes on an execution agent belonging to the associated
execution context of <code class="highlight"><c- n>sch</c-></code> and sends signals equivalent to those sent by <code class="highlight"><c- n>s</c-></code>, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>When a receiver completion-signal <code class="highlight"><i><c- n>Signal</c-></i><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, it constructs a receiver <code class="highlight"><c- n>r2</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r2</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><i><c- n>Signal</c-></i><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r2</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done</c-><c- p>(</c-><c- n>r2</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
         <p>It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>)</c-></code>, resulting in a sender <code class="highlight"><c- n>s3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s3</c-><c- p>,</c-> <c- n>r2</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state3</c-><c- p>)</c-></code>. If any of these throws an exception,
it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>. The lifetime of <code class="highlight"><c- n>op_state3</c-></code> ends when <code class="highlight"><c- n>op_state</c-></code> is destroyed.</p>
       </ol>
     </ol>
    <li data-md>
     <p>Senders returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer</c-></code> shall not propagate the sender queries <code class="highlight"><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code> to an input sender. They shall return a scheduler equivalent to the <code class="highlight"><c- n>sch</c-></code> argument from those queries.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.6" id="spec-execution.senders.adaptor.then"><span class="secno">9.6.5.6. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> <b>[execution.senders.adaptors.then]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.then"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> is used to attach invocables as continuation for successful completion of the input sender.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> and passes the result <code class="highlight"><c- n>v</c-></code> to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>v</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> with the result of the <code class="highlight"><c- n>set_value</c-></code> signal of <code class="highlight"><c- n>s</c-></code>, passing the return value as the value to any connected receivers, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.7" id="spec-execution.senders.adaptor.upon_error"><span class="secno">9.6.5.7. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-></code> <b>[execution.senders.adaptors.upon_error]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.upon_error"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-></code> is used to attach invocables as continuation for unsuccessul completion of the input sender.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_error_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>upon_error</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> and passes the result <code class="highlight"><c- n>v</c-></code> to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>v</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> with the result of the <code class="highlight"><c- n>set_error</c-></code> signal of <code class="highlight"><c- n>s</c-></code>, passing the return value as the value to any connected receivers, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.8" id="spec-execution.senders.adaptor.upon_done"><span class="secno">9.6.5.8. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code> <b>[execution.senders.adaptors.upon_done]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.upon_done"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code> is used to attach invocables as continuation for the completion of the input sender using the "done" channel.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_done_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>upon_done</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>)</c-></code> and passes the result <code class="highlight"><c- n>v</c-></code> to <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>v</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> when the <code class="highlight"><c- n>set_done</c-></code> signal of <code class="highlight"><c- n>s</c-></code> is called, passing the return value as the value to any connected receivers, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.9" id="spec-execution.senders.adaptors.let_value"><span class="secno">9.6.5.9. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-></code> <b>[execution.senders.adaptors.let_value]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.let_value"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-></code> is used to insert continuations creating more work dependent on the results of their input senders into a sender chain.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_value</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, copies <code class="highlight"><c- n>args</c-><c- p>...</c-></code> into <code class="highlight"><c- n>op_state2</c-></code> as <code class="highlight"><c- n>args2</c-><c- p>...</c-></code>, then calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>,</c-> <c- n>args2</c-><c- p>...)</c-></code>, resulting in a sender <code class="highlight"><c- n>s3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s3</c-><c- p>,</c-> <c- n>out_r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state3</c-></code>. <code class="highlight"><c- n>op_state3</c-></code> is saved as a part of <code class="highlight"><c- n>op_state2</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state3</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> when <code class="highlight"><c- n>set_value</c-></code> is called, and making its completion dependent on the completion of a sender returned by <code class="highlight"><c- n>f</c-></code>, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.10" id="spec-execution.senders.adaptors.let_error"><span class="secno">9.6.5.10. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-></code> <b>[execution.senders.adaptors.let_error]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.let_error"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-></code> is used to insert continuations creating more work dependent on the results of their input senders into a sender chain.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_error_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_error</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, copies <code class="highlight"><c- n>e</c-></code> into <code class="highlight"><c- n>op_state2</c-></code> as <code class="highlight"><c- n>e</c-></code>, then calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>, resulting in a sender <code class="highlight"><c- n>s3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s3</c-><c- p>,</c-> <c- n>out_r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state3</c-></code>. <code class="highlight"><c- n>op_state3</c-></code> is saved
as a part of <code class="highlight"><c- n>op_state2</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state3</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> when <code class="highlight"><c- n>set_error</c-></code> is called, and making its completion dependent on the completion of a sender returned by <code class="highlight"><c- n>f</c-></code>, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.11" id="spec-execution.senders.adaptors.let_done"><span class="secno">9.6.5.11. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code> <b>[execution.senders.adaptors.let_done]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.let_done"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code> is used to insert continuations creating more work dependent on the results of their input senders into a sender chain.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_done_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>invoke</c-><c- p>(</c-><c- n>f</c-><c- p>)</c-></code>, resulting in a sender <code class="highlight"><c- n>s3</c-></code>. It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s3</c-><c- p>,</c-> <c- n>out_r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state3</c-></code>. <code class="highlight"><c- n>op_state3</c-></code> is saved as a part of <code class="highlight"><c- n>op_state2</c-></code>.
It then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state3</c-><c- p>)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>. which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-></code> when <code class="highlight"><c- n>set_done</c-></code> is called, and making its completion dependent on the completion of a sender returned by <code class="highlight"><c- n>f</c-></code>, and propagates the other completion-signals sent by <code class="highlight"><c- n>s</c-></code>, the program is
    ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.12" id="spec-execution.senders.adaptors.bulk"><span class="secno">9.6.5.12. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code> <b>[execution.senders.adaptors.bulk]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.bulk"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code> is used to run a task repeatedly for every index in an index space.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-></code>, <code class="highlight"><c- n>shape</c-></code>, and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>, <code class="highlight"><c- n>Shape</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>shape</c-><c- p>))</c-></code>, and <code class="highlight"><c- n>F</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>f</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code> or <code class="highlight"><c- n>Shape</c-></code> does not satisfy <code class="highlight"><c- n>integral</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>shape</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>,</c-> <c- n>shape</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>bulk</c-><c- p>,</c-> <c- n>s</c-><c- p>,</c-> <c- n>shape</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>f</c-><c- p>(</c-><c- n>i</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> for each <code class="highlight"><c- n>i</c-></code> of type <code class="highlight"><c- n>Shape</c-></code> from <code class="highlight"><c- mi>0</c-></code> to <code class="highlight"><c- n>shape</c-></code>, then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>. If any of these throws an exception, it catches it and calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>current_exception</c-><c- p>())</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, which results in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which invokes <code class="highlight"><c- n>f</c-><c- p>(</c-><c- n>i</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> for each <code class="highlight"><c- n>i</c-></code> of type <code class="highlight"><c- n>Shape</c-></code> from <code class="highlight"><c- mi>0</c-></code> to <code class="highlight"><c- n>shape</c-></code> when the input sender sends values <code class="highlight"><c- n>args</c-><c- p>...</c-></code>, or does not propagate the values of the signals sent by the input sender to
    a connected receiver, the program is ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.13" id="spec-execution.senders.adaptors.split"><span class="secno">9.6.5.13. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code> <b>[execution.senders.adaptors.split]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.split"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code> is used to adapt an arbitrary sender into a sender that can be connected multiple times.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>split</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>split</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>split</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s2</c-></code>, which:</p>
       <ol>
        <li data-md>
         <p>Creates an object <code class="highlight"><c- n>sh_state</c-></code>. The lifetime of <code class="highlight"><c- n>sh_state</c-></code> shall last for at least as long as the lifetime of the last operation state object returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>some_r</c-><c- p>)</c-></code> for some receiver <code class="highlight"><c- n>some_r</c-></code>.</p>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> is called, saves the expressions <code class="highlight"><c- n>args</c-><c- p>...</c-></code> as subobjects of <code class="highlight"><c- n>sh_state</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, saves the expression <code class="highlight"><c- n>e</c-></code> as a subobject of <code class="highlight"><c- n>sh_state</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, saves this fact in <code class="highlight"><c- n>sh_state</c-></code>.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state2</c-></code>. <code class="highlight"><c- n>op_state2</c-></code> is saved as a subobject of <code class="highlight"><c- n>sh_state</c-></code>.</p>
        <li data-md>
         <p>When <code class="highlight"><c- n>s2</c-></code> is connected with a receiver <code class="highlight"><c- n>out_r</c-></code>, it returns an operation state object <code class="highlight"><c- n>op_state</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>, if this is the first time this expression would be evaluated. When both <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> and <code class="highlight"><i><c- n>Signal</c-></i><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code> have been called, calls <code class="highlight"><i><c- n>Signal</c-></i><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>args2</c-><c- p>...)</c-></code>, where <code class="highlight"><c- n>args2</c-><c- p>...</c-></code> is a pack of lvalues referencing the subobjects of <code class="highlight"><c- n>sh_state</c-></code> that have been saved by the
original call to <code class="highlight"><i><c- n>Signal</c-></i><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>args</c-><c- p>...)</c-></code>.</p>
       </ol>
     </ol>
     <p>If the function selected above does not return a sender which sends references to values sent by <code class="highlight"><c- n>s</c-></code>, propagating the other channels, the program is ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.14" id="spec-execution.senders.adaptor.when_all"><span class="secno">9.6.5.14. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> <b>[execution.senders.adaptors.when_all]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.when_all"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> is used to join multiple sender chains and create a sender whose execution is dependent on all of the input senders that only send a single set of values. <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-></code> is used to join multiple sender chains and create a sender whose execution is dependent on all of the input senders, which may have one or more sets of sent values.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If any type <code class="highlight"><c- n>S</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>S</c-><c- p>...</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, or the number of the arguments <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><i><sub><c- n>i</c-></sub></i><c- o>>::</c-><c- n>value_types</c-></code> passes into the <code class="highlight"><c- n>Variant</c-></code> template parameter is not 1, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-><c- p>(</c-><c- n>s</c-><c- p>...)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-><c- p>,</c-> <c- n>s</c-><c- p>...)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender which sends a concatenation of values sent by <code class="highlight"><c- n>s</c-><c- p>...</c-></code> when they all complete with <code class="highlight"><c- n>set_value</c-></code>, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, constructs a sender <code class="highlight"><c- n>s</c-></code>. When <code class="highlight"><c- n>s</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
       <ol>
        <li data-md>
         <p>For each sender <code class="highlight"><c- n>s</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, constructs a receiver <code class="highlight"><c- n>r</c-><sub><i><c- n>i</c-></i></sub></code>:</p>
         <ol start="2">
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><sub><i><c- n>i</c-></i></sub><c- p>,</c-> <c- n>t</c-><sub><i><c- n>i</c-></i></sub><c- p>...)</c-></code> is called for every <code class="highlight"><c- n>r</c-><sub><i><c- n>i</c-></i></sub></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>t</c-><sub><i><c- n>0</c-></i></sub><c- p>...,</c-> <c- n>t</c-><sub><i><c- n>1</c-></i></sub><c- p>...,</c-> <c- p>...,</c-> <c- n>t</c-><sub><i><c- n>n</c-></i></sub><c- p>...)</c-></code> is called, where <code class="highlight"><c- n>n</c-></code> is <code class="highlight"><c- k>sizeof</c-><c- p>...(</c-><c- n>s</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-></code>.</p>
          <li data-md>
           <p>Otherwise, if <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><sub><i><c- n>i</c-></i></sub><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called for any <code class="highlight"><c- n>r</c-><sub><i><c- n>i</c-></i></sub></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called.</p>
          <li data-md>
           <p>Otherwise, if <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><sub><i><c- n>i</c-></i></sub><c- p>)</c-></code> is called for any <code class="highlight"><c- n>r</c-><sub><i><c- n>i</c-></i></sub></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code> is called.</p>
         </ol>
        <li data-md>
         <p>For each sender <code class="highlight"><c- n>s</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><sub><i><c- n>i</c-></i></sub><c- p>,</c-> <c- n>r</c-><sub><i><c- n>i</c-></i></sub><c- p>)</c-></code>, resulting in operation states <code class="highlight"><c- n>op_state</c-><sub><i><c- n>i</c-></i></sub></code>.</p>
        <li data-md>
         <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains each operation state <code class="highlight"><c- n>op_state</c-><sub><i><c- n>i</c-></i></sub></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><sub><i><c- n>i</c-></i></sub><c- p>)</c-></code> for each <code class="highlight"><c- n>op_state</c-><sub><i><c- n>i</c-></i></sub></code>.</p>
       </ol>
     </ol>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If any type <code class="highlight"><c- n>S</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>S</c-><c- p>...</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-><c- p>(</c-><c- n>s</c-><c- p>...)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>when_all_with_variant</c-><c- p>,</c-> <c- n>s</c-><c- p>...)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender which sends the types <code class="highlight"><i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>...</c-></code> when they all complete with <code class="highlight"><c- n>set_value</c-></code>, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>when_all</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-><c- p>(</c-><c- n>s</c-><c- p>)...)</c-></code>.</p>
     </ol>
    <li data-md>
     <p>Senders returned from adaptors defined in this subclause shall not expose the sender queries <code class="highlight"><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code>.</p>
    <li data-md>
     <p><code class="highlight"><c- n>tag_invoke</c-></code> expressions used in the definitions of the sender adaptors in this subclause shall not consider member functions of their first non-tag arguments.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.15" id="spec-execution.senders.adaptor.transfer_when_all"><span class="secno">9.6.5.15. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> <b>[execution.senders.adaptors.transfer_when_all]</b></span><a class="self-link" href="#spec-execution.senders.adaptor.transfer_when_all"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> is used to join multiple sender chains and create a sender whose execution is dependent on all of the input senders that only send a single set of values each, while also making sure
that they complete on the specified scheduler. <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all_with_variant</c-></code> is used to join multiple sender chains and create a sender whose execution is dependent on all of the input
senders, which may have one or more sets of sent values. [<i>Note:</i> this can allow for better customization of the adaptors. --<i>end note</i>]</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>sch</c-></code> and <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, let <code class="highlight"><c- n>Sch</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- n>sch</c-><c- p>)</c-></code> and <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>Sch</c-></code> does not satisfy <code class="highlight"><c- n>scheduler</c-></code>, or any type <code class="highlight"><c- n>S</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>S</c-><c- p>...</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, or the number of the arguments <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><i><sub><c- n>i</c-></sub></i><c- o>>::</c-><c- n>value_types</c-></code> passes into the <code class="highlight"><c- n>Variant</c-></code> template parameter is not 1, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>...)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-><c- p>,</c-> <c- n>sch</c-><c- p>,</c-> <c- n>s</c-><c- p>...)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender which sends a concatenation of values sent by <code class="highlight"><c- n>s</c-><c- p>...</c-></code> when
they all complete with <code class="highlight"><c- n>set_value</c-></code>, or does not send its completion signals, other than ones resulting from a scheduling error, on an execution agent belonging to the associated execution context of <code class="highlight"><c- n>sch</c-></code>, the program is ill-formed with no diagnostic
required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>transfer</c-><c- p>(</c-><c- n>when_all</c-><c- p>(</c-><c- n>s</c-><c- p>...),</c-> <c- n>sch</c-><c- p>)</c-></code>.</p>
     </ol>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all_with_variant</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>s</c-><c- p>...</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If any type <code class="highlight"><c- n>S</c-><i><sub><c- n>i</c-></sub></i></code> in <code class="highlight"><c- n>S</c-><c- p>...</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all_with_variant</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all_with_variant</c-><c- p>(</c-><c- n>s</c-><c- p>...)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all_with_variant</c-><c- p>,</c-> <c- n>s</c-><c- p>...)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not return a sender which sends the types <code class="highlight"><i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>...</c-></code> when they all complete with <code class="highlight"><c- n>set_value</c-></code>, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-><c- p>(</c-><c- n>sch</c-><c- p>,</c-> <c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-><c- p>(</c-><c- n>s</c-><c- p>)...)</c-></code>.</p>
     </ol>
    <li data-md>
     <p>Senders returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>transfer_when_all</c-></code> shall not propagate the sender queries <code class="highlight"><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>CPO</c-><c- o>></c-></code> to input senders. They shall return a scheduler equivalent to the <code class="highlight"><c- n>sch</c-></code> argument from those queries.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.16" id="spec-execution.senders.adaptors.into_variant"><span class="secno">9.6.5.16. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code> <b>[execution.senders.adaptors.into_variant]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.into_variant"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code> can be used to turn a typed sender which sends multiple sets of values into a sender which sends a variant of all of those sets of values.</p>
    <li data-md>
     <p>The template <code class="highlight"><i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i></code> is used to compute the type sent by a sender returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code>.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
  <c- k>using</c-> <i><c- n>into</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c->
    <c- k>typename</c-> <c- nc>execution</c-><c- o>::</c-><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>></c->
      <c- o>::</c-><c- k>template</c-> <c- n>value_types</c-><c- o>&lt;</c-><c- n>tuple</c-><c- p>,</c-> <c- n>variant</c-><c- o>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
  <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>into_variant</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>);</c->
</pre>
    <li data-md>
     <p><i>Effects:</i> Returns a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it:</p>
     <ol>
      <li data-md>
       <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
       <ol>
        <li data-md>
         <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>ts</c-><c- p>...)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>(</c-><c- n>make_tuple</c-><c- p>(</c-><c- n>ts</c-><c- p>...)))</c-></code>.</p>
        <li data-md>
         <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
        <li data-md>
         <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
       </ol>
      <li data-md>
       <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state2</c-></code>.</p>
      <li data-md>
       <p>Returns an operation state <code class="highlight"><c- n>op_state</c-></code> that contains <code class="highlight"><c- n>op_state2</c-></code>. When <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code> is called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code>.</p>
     </ol>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.17" id="spec-execution.senders.adaptors.done_as_optional"><span class="secno">9.6.5.17. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> <b>[execution.senders.adaptors.done_as_optional]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.done_as_optional"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> is used to handle a done signal by mapping it into the value channel as an empty optional. The value channel is also converted into an optional. The result is a sender that never completes with done, reporting cancellation by completing with an empty optional.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-><c- p>.</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If the type <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_optional</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
<pre class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>let_done</c-><c- p>(</c->
  <c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- p>[](</c-><c- k>auto</c-><c- o>&amp;&amp;</c-> <c- n>t</c-><c- p>)</c-> <c- p>{</c->
      <c- k>return</c-> <c- n>optional</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>>></c-><c- p>{</c->
        <c- k>static_cast</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>t</c-><c- p>)</c-><c- o>></c-><c- p>(</c-><c- n>t</c-><c- p>)</c->
      <c- p>};</c->
    <c- p>}</c->
  <c- p>),</c->
  <c- p>[]</c-> <c- p>()</c-> <c- k>noexcept</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>execution</c-><c- o>::</c-><c- n>just</c-><c- p>(</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>decay_t</c-><c- o>&lt;</c-><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>>></c-><c- p>{});</c->
  <c- p>}</c->
<c- p>)</c->
</pre>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.18" id="spec-execution.senders.adaptors.done_as_error"><span class="secno">9.6.5.18. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code> <b>[execution.senders.adaptors.done_as_error]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.done_as_error"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>done_as_error</c-></code> is used to handle a done signal by mapping it into the error channel as an <code class="highlight"><c- n>exception_ptr</c-></code> that refers to a custom exception type. The result is a sender that never completes with done, reporting cancellation by completing with an error.</p>
    <li data-md>
     <p>The template <code class="highlight"><i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i></code> is used to compute the type sent by a sender returned from <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-></code>.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>move_constructible</c-> <c- n>Error</c-><c- p>,</c-> <c- n>sender</c-> <c- n>S</c-><c- o>></c->
  <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>done_as_error</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>Error</c-> <c- n>err</c-> <c- o>=</c-> <c- n>Error</c-><c- p>{});</c->
</pre>
    <li data-md>
     <p><i>Effects:</i> Equivalent to:</p>
<pre class="highlight"><c- k>return</c-> <c- n>execution</c-><c- o>::</c-><c- n>let_done</c-><c- p>(</c->
  <c- k>static_cast</c-><c- o>&lt;</c-><c- n>S</c-><c- o>&amp;&amp;></c-><c- p>(</c-><c- n>s</c-><c- p>),</c->
  <c- p>[</c-><c- n>err2</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>err</c-><c- p>)]</c-> <c- p>()</c-> <c- k>mutable</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>execution</c-><c- o>::</c-><c- n>just_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>err2</c-><c- p>));</c->
  <c- p>}</c->
<c- p>)</c->
</pre>
   </ol>
   <h5 class="heading settled" data-level="9.6.5.19" id="spec-execution.senders.adaptors.ensure_started"><span class="secno">9.6.5.19. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> <b>[execution.senders.adaptors.ensure_started]</b></span><a class="self-link" href="#spec-execution.senders.adaptors.ensure_started"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> is used to eagerly start the execution of a sender, while also providing a way to attach further work to execute once it has completed.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-><c- p>,</c-> <c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type satisfies <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>.</p>
      <li data-md>
       <p>Otherwise:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in operation state <code class="highlight"><c- n>op_state</c-></code>, and then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code>.</p>
        <li data-md>
         <p>Constructs a sender <code class="highlight"><c- n>s2</c-></code>. When <code class="highlight"><c- n>s2</c-></code> is connected with some receiver <code class="highlight"><c- n>out_r</c-></code>, it results in an operation state <code class="highlight"><c- n>op_state2</c-></code>. Once both <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state2</c-><c- p>)</c-></code> and one of the receiver completion-signals has been called on <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>ts</c-><c- p>...)</c-></code> has been called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>ts</c-><c- p>...)</c-></code>.</p>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> has been called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>out_r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code>.</p>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> has been called, calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>out_r</c-><c- p>)</c-></code>.</p>
         </ol>
         <p>The lifetime of <code class="highlight"><c- n>op_state</c-></code> lasts until all three of the following have occured:</p>
         <ol>
          <li data-md>
           <p>the lifetime of <code class="highlight"><c- n>op_state2</c-></code> has ended,</p>
          <li data-md>
           <p>the lifetime of <code class="highlight"><c- n>s2</c-></code> has ended, and</p>
          <li data-md>
           <p>a receiver completion-signal has been called on <code class="highlight"><c- n>r</c-></code>.</p>
         </ol>
       </ol>
     </ol>
     <p>If the function selected above does not eagerly start the sender <code class="highlight"><c- n>s</c-></code> and return a sender which propagates the signals sent by <code class="highlight"><c- n>s</c-></code> once started, the program is ill-formed with no diagnostic required.</p>
   </ol>
   <p class="note" role="note"><span>Note:</span> The wording for <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>ensure_started</c-></code> is incomplete as it does not currently describe the required
semantics for sending a stop-request to the eagerly-launched operation if the sender is destroyed and detaches
from the operation before the operation completes.</p>
   <h4 class="heading settled" data-level="9.6.6" id="spec-execution.senders.consumers"><span class="secno">9.6.6. </span><span class="content">Sender consumers <b>[execution.senders.consumers]</b></span><a class="self-link" href="#spec-execution.senders.consumers"></a></h4>
   <h5 class="heading settled" data-level="9.6.6.1" id="spec-execution.senders.consumers.start_detached"><span class="secno">9.6.6.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code> <b>[execution.senders.consumer.start_detached]</b></span><a class="self-link" href="#spec-execution.senders.consumers.start_detached"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code> is used to eagerly start a sender without the caller needing to manage the lifetimes of any objects.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>sender</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-></code> is ill-formed. Otherwise, the expression <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-><c- p>,</c-> <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type is <code class="highlight"><c- b>void</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if that expression is valid and its type is <code class="highlight"><c- b>void</c-></code>.</p>
      <li data-md>
       <p>Otherwise:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>:</p>
         <ol>
          <li data-md>
           <p>When <code class="highlight"><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>ts</c-><c- p>...)</c-></code> is called, it does nothing.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is called, it calls <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>terminate</c-></code>.</p>
          <li data-md>
           <p>When <code class="highlight"><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is called, it does nothing.</p>
         </ol>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state</c-></code>, then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code>. The lifetime of <code class="highlight"><c- n>op_state</c-></code> lasts until one of the receiver completion-signals of <code class="highlight"><c- n>r</c-></code> is called.</p>
       </ol>
     </ol>
     <p>If the function selected above does not eagerly start the sender <code class="highlight"><c- n>s</c-></code> after connecting it with a receiver which ignores the <code class="highlight"><c- n>set_value</c-></code> and <code class="highlight"><c- n>set_done</c-></code> signals and calls <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>terminate</c-></code> on the <code class="highlight"><c- n>set_error</c-></code> signal, the program is ill-formed with no diagnostic required.</p>
   </ol>
   <h5 class="heading settled" data-level="9.6.6.2" id="spec-execution.senders.consumers.sync_wait"><span class="secno">9.6.6.2. </span><span class="content"><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> <b>[execution.senders.consumers.sync_wait]</b></span><a class="self-link" href="#spec-execution.senders.consumers.sync_wait"></a></h5>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> and <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-></code> are used to block a current thread until a sender passed into it as an argument has completed, and to obtain the values (if any) it completed with.</p>
    <li data-md>
     <p>The templates <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i></code> and <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i></code> are used to determine the return types of <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> and <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-></code>.</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
  <c- k>using</c-> <i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <c- n>optional</c-><c- o>&lt;</c->
    <c- k>typename</c-> <c- nc>execution</c-><c- o>::</c-><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>></c->
      <c- o>::</c-><c- k>template</c-> <c- n>value_types</c-><c- o>&lt;</c-><c- n>tuple</c-><c- p>,</c-> <c- n>type_identity_t</c-><c- o>>></c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- n>typed_sender</c-> <c- n>S</c-><c- o>></c->
  <c- k>using</c-> <i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <c- n>optional</c-><c- o>&lt;</c-><i><c- n>into</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>>></c-><c- p>;</c->
</pre>
    <li data-md>
     <p>The name <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, or the number of the arguments <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>::</c-><c- n>value_types</c-></code> passes into the <code class="highlight"><c- n>Variant</c-></code> template parameter is not 1, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>,</c-> <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>)</c-></code>, if this expression is valid and its type is <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if this expression is valid and its type is <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code>.</p>
      <li data-md>
       <p>Otherwise:</p>
       <ol>
        <li data-md>
         <p>Constructs a receiver <code class="highlight"><c- n>r</c-></code>.</p>
        <li data-md>
         <p>Calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>r</c-><c- p>)</c-></code>, resulting in an operation state <code class="highlight"><c- n>op_state</c-></code>, then calls <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- p>(</c-><c- n>op_state</c-><c- p>)</c-></code>.</p>
        <li data-md>
         <p>Blocks the current thread until a receiver completion-signal of <code class="highlight"><c- n>r</c-></code> is called. When it is:</p>
         <ol>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>ts</c-><c- p>...)</c-></code> has been called, returns <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>(</c-><c- n>make_tuple</c-><c- p>(</c-><c- n>ts</c-><c- p>...))</c-><c- o>></c-></code>.</p>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>...)</c-></code> has been called, if <code class="highlight"><c- n>remove_cvref_t</c-><c- p>(</c-><c- k>decltype</c-><c- p>(</c-><c- n>e</c-><c- p>))</c-></code> is <code class="highlight"><c- n>exception_ptr</c-></code>, calls <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>rethrow_exception</c-><c- p>(</c-><c- n>e</c-><c- p>)</c-></code>. Otherwise, throws <code class="highlight"><c- n>e</c-></code>.</p>
          <li data-md>
           <p>If <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> has been called, returns <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- p>(</c-><c- n>nullopt</c-><c- p>)</c-><c- o>></c-></code>.</p>
         </ol>
       </ol>
     </ol>
    <li data-md>
     <p>The name <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-></code> denotes a customization point object. For some subexpression <code class="highlight"><c- n>s</c-></code>, let <code class="highlight"><c- n>S</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>S</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>typed_sender</c-></code>, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-><c- p>,</c-> <c- n>execution</c-><c- o>::</c-><c- n>get_completion_scheduler</c-><c- o>&lt;</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-><c- o>></c-><c- p>(</c-><c- n>s</c-><c- p>),</c-> <c- n>s</c-><c- p>)</c-></code>, if this expression is valid and its type is <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait_with_variant</c-><c- p>,</c-> <c- n>s</c-><c- p>)</c-></code>, if this expression is valid and its type is <code class="highlight"><i><c- n>sync</c-><c- o>-</c-><c- n>wait</c-><c- o>-</c-><c- n>with</c-><c- o>-</c-><c- n>variant</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>this_thread</c-><c- o>::</c-><c- n>sync_wait</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>into_variant</c-><c- p>(</c-><c- n>s</c-><c- p>))</c-></code>.</p>
     </ol>
    <li data-md>
     <p>Any receiver <code class="highlight"><c- n>r</c-></code> created by an implementation of <code class="highlight"><c- n>sync_wait</c-></code> and <code class="highlight"><c- n>sync_wait_with_variant</c-></code> shall implement the <code class="highlight"><c- n>get_scheduler</c-></code> receiver query. The scheduler returned from the query for the receiver created by the default implementation shall return an
implementation-defined scheduler that is driven by the waiting thread, such that scheduled tasks run on the thread of the caller.</p>
   </ol>
   <h3 class="heading settled" data-level="9.7" id="spec-execution.execute"><span class="secno">9.7. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> <b>[execution.execute]</b></span><a class="self-link" href="#spec-execution.execute"></a></h3>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> is used to create fire-and-forget tasks on a specified scheduler.</p>
    <li data-md>
     <p>The name <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> denotes a customization point object. For some subexpressions <code class="highlight"><c- n>sch</c-></code> and <code class="highlight"><c- n>f</c-></code>, let <code class="highlight"><c- n>Sch</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>sch</c-><c- p>))</c-></code> and <code class="highlight"><c- n>F</c-></code> be <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>f</c-><c- p>))</c-></code>. If <code class="highlight"><c- n>Sch</c-></code> does not satisfy <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>scheduler</c-></code> or <code class="highlight"><c- n>F</c-></code> does not satisfy <code class="highlight"><c- n>invocable</c-><c- o>&lt;></c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> is ill-formed. Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> is expression-equivalent to:</p>
     <ol>
      <li data-md>
       <p><code class="highlight"><c- n>tag_invoke</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>,</c-> <c- n>sch</c-><c- p>,</c-> <c- n>f</c-><c- p>)</c-></code>, if that expression is valid and its type is <code class="highlight"><c- b>void</c-></code>. If the function selected by <code class="highlight"><c- n>tag_invoke</c-></code> does not invoke the function <code class="highlight"><c- n>f</c-></code> on an execution agent belonging to the associated execution context of <code class="highlight"><c- n>sch</c-></code>, or if it
does not call <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>terminate</c-></code> if an error occurs after control is returned to the caller, the program is ill-formed with no diagnostic required.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>start_detached</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>then</c-><c- p>(</c-><c- n>execution</c-><c- o>::</c-><c- n>schedule</c-><c- p>(</c-><c- n>sch</c-><c- p>),</c-> <c- n>f</c-><c- p>))</c-></code>.</p>
     </ol>
   </ol>
   <h3 class="heading settled" data-level="9.8" id="spec-execution.coro_utils"><span class="secno">9.8. </span><span class="content">Coroutine utilities <b>[execution.coro_utils]</b></span><a class="self-link" href="#spec-execution.coro_utils"></a></h3>
   <h4 class="heading settled" data-level="9.8.1" id="spec-execution.coro_utils.as_awaitable"><span class="secno">9.8.1. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>as_awaitable</c-></code> <b>[execution.coro_utils.as_awaitable]</b></span><a class="self-link" href="#spec-execution.coro_utils.as_awaitable"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>as_awaitable</c-></code> is used to wrap a sender into an object that is awaitable within a particular coroutine. A sender <code class="highlight"><c- n>s</c-></code> of type <code class="highlight"><c- n>S</c-></code> can be made awaitable if and only if:</p>
     <ul>
      <li data-md>
       <p><code class="highlight"><c- n>S</c-></code> models the concept <code class="highlight"><c- n>typed_sender</c-></code>, and</p>
      <li data-md>
       <p>It calls at most one overload of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-></code> with zero or one argument, and</p>
      <li data-md>
       <p>It calls at most one overload of <code class="highlight"><c- n>exception</c-><c- o>::</c-><c- n>set_error</c-></code>, and</p>
      <li data-md>
       <p>Given an lvalue <code class="highlight"><c- n>p</c-></code> to the promise type of an awaiting coroutine, <code class="highlight"><c- n>p</c-><c- p>.</c-><c- n>unhandled_done</c-><c- p>()</c-></code> is well-formed, <code class="highlight"><c- k>noexcept</c-></code>, and returns a type convertible to <code class="highlight"><c- n>coroutine_handle</c-><c- o>&lt;></c-></code>.</p>
     </ul>
<pre class="highlight"><c- c1>// exposition only</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>using</c-> <i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i> <c- o>=</c-> <i><c- n>see</c-> <c- n>below</c-></i><c- p>;</c->

<c- c1>// exposition only</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>S</c-><c- o>></c->
  <c- k>concept</c-> <i><c- nc>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i> <c- o>=</c->
    <c- n>typed_sender</c-><c- o>&lt;</c-><c- n>S</c-><c- o>></c-> <c- o>&amp;&amp;</c->
    <c- k>requires</c-> <c- p>{</c-> <c- k>typename</c-> <i><c- nc>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>;</c-> <c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i> <c- n>Sender</c-><c- p>,</c-> <c- k>class</c-> <c- nc>Promise</c-><c- o>></c->
  <i><c- n>unspecified</c-></i> <c- n>as_awaitable</c-><c- p>(</c-><c- n>Sender</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>Promise</c-><c- o>&amp;</c-> <c- n>p</c-><c- p>);</c->
</pre>
    <li data-md>
     <p>Alias template <i>single-sender-value-type</i> is defined as follows:</p>
     <ol>
      <li data-md>
       <p>If <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>>::</c-><c- n>value_types</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- p>,</c-> <c- n>Variant</c-><c- o>></c-></code> would have the form <code class="highlight"><c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code>, then <code class="highlight"><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is an alias for type <code class="highlight"><c- n>T</c-></code>.</p>
      <li data-md>
       <p>Otherwise, if <code class="highlight"><c- n>sender_traits</c-><c- o>&lt;</c-><c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>S</c-><c- o>>>::</c-><c- n>value_types</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- p>,</c-> <c- n>Variant</c-><c- o>></c-></code> would have the form <code class="highlight"><c- n>Variant</c-><c- o>&lt;</c-><c- n>Tuple</c-><c- o>&lt;>></c-></code> or <code class="highlight"><c- n>Variant</c-><c- o>&lt;></c-></code>, then <code class="highlight"><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-></code> is an alias for type <code class="highlight"><c- b>void</c-></code>.</p>
      <li data-md>
       <p>Otherwise, <code class="highlight"><i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-></code> is ill-formed.</p>
     </ol>
    <li data-md>
     <p>For some expressions <code class="highlight"><c- n>s</c-></code> and <code class="highlight"><c- n>p</c-></code> such that <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>s</c-><c- p>))</c-></code> is <code class="highlight"><c- n>S</c-></code> and <code class="highlight"><c- k>decltype</c-><c- p>((</c-><c- n>p</c-><c- p>))</c-></code> is <code class="highlight"><c- n>P</c-><c- o>&amp;</c-></code>, <code class="highlight"><c- n>as_awaitable</c-><c- p>(</c-><c- n>s</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code> returns <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i><c- p>{</c-><c- n>s</c-><c- p>,</c-> <c- n>p</c-><c- p>}</c-></code>, where <code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i></code> is an unspecified class type equivalant to the following:</p>
<pre class="highlight"><c- k>class</c-> <i><c- nc>sender</c-><c- o>-</c-><c- n>awaitable</c-></i> <c- p>{</c->
  <c- k>struct</c-> <c- nc>unit</c-> <c- p>{};</c-> <c- c1>// exposition only</c->
  <c- k>using</c-> <c- n>value_t</c-> <c- o>=</c-> <i><c- n>single</c-><c- o>-</c-><c- n>sender</c-><c- o>-</c-><c- n>value</c-><c- o>-</c-><c- n>type</c-></i><c- o>&lt;</c-><c- n>S</c-><c- o>></c-><c- p>;</c->
  <c- k>using</c-> <c- n>result_t</c-> <c- o>=</c-> <c- n>conditional_t</c-><c- o>&lt;</c-><c- n>is_void_v</c-><c- o>&lt;</c-><c- n>value_t</c-><c- o>></c-><c- p>,</c-> <c- n>unit</c-><c- p>,</c-> <c- n>value_t</c-><c- o>></c-><c- p>;</c->
  <c- k>struct</c-> <i><c- nc>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i><c- p>;</c-> <c- c1>// exposition only</c->

  <c- n>variant</c-><c- o>&lt;</c-><c- n>monostate</c-><c- p>,</c-> <c- n>result_t</c-><c- p>,</c-> <c- n>exception_ptr</c-><c- o>></c-> <c- n>result_</c-><c- p>{};</c-> <c- c1>// exposition only</c->
  <c- n>connect_result_t</c-><c- o>&lt;</c-><c- n>S</c-><c- p>,</c-> <i><c- n>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i><c- o>></c-> <c- n>state_</c-><c- p>;</c->  <c- c1>// exposition only</c->

 <c- k>public</c-><c- o>:</c->
  <i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i><c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>P</c-><c- o>&amp;</c-> <c- n>p</c-><c- p>);</c->
  <c- b>bool</c-> <c- nf>await_ready</c-><c- p>()</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> false<c- p>;</c-> <c- p>}</c->
  <c- b>void</c-> <c- nf>await_suspend</c-><c- p>(</c-><c- n>coro</c-><c- o>::</c-><c- n>coroutine_handle</c-><c- o>&lt;></c-><c- p>)</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- n>start</c-><c- p>(</c-><c- n>state_</c-><c- p>);</c-> <c- p>}</c->
  <c- n>value_t</c-> <c- nf>await_resume</c-><c- p>();</c->
<c- p>};</c->
</pre>
     <ol>
      <li data-md>
       <p><code class="highlight"><i><c- n>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i></code> is a receiver type equivalent to the following:</p>
<pre class="highlight"><c- k>struct</c-> <i><c- nc>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i> <c- p>{</c-> <c- c1>// exposition only</c->
  <c- n>variant</c-><c- o>&lt;</c-><c- n>monostate</c-><c- p>,</c-> <c- n>result_t</c-><c- p>,</c-> <c- n>exception_ptr</c-><c- o>>*</c-> <c- n>result_ptr_</c-><c- p>;</c->
  <c- n>coroutine_handle</c-><c- o>&lt;</c-><c- n>P</c-><c- o>></c-> <c- n>continuation_</c-><c- p>;</c->
  <c- c1>// ... </c-><i><c- c1>see below</c-></i>
<c- p>};</c->
</pre>
       <p>Let <code class="highlight"><c- n>r</c-></code> be an rvalue expression of type <code class="highlight"><i><c- n>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i></code>, let <code class="highlight"><c- n>v</c-></code> be an expression of type <code class="highlight"><c- n>result_t</c-></code>, let <code class="highlight"><c- n>e</c-></code> be an arbitrary expression of type <code class="highlight"><c- n>E</c-></code>, let <code class="highlight"><c- n>p</c-></code> be an lvalue reference to the coroutine promise type, let <code class="highlight"><c- n>c</c-></code> be a customization point object, and let <code class="highlight"><c- n>as</c-><c- p>...</c-></code> be a pack of arguments. Then:</p>
       <ol>
        <li data-md>
         <p>If <code class="highlight"><c- n>value_t</c-></code> is <code class="highlight"><c- b>void</c-></code>, then <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is expression-equivalent to <code class="highlight"><c- p>(</c-><c- n>result_ptr_</c-><c- o>-></c-><c- n>emplace</c-><c- o>&lt;</c-><c- mi>1</c-><c- o>></c-><c- p>(),</c-> <c- n>continuation_</c-><c- p>.</c-><c- n>resume</c-><c- p>())</c-></code>; otherwise, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>v</c-><c- p>)</c-></code> is expression-equivalent to <code class="highlight"><c- p>(</c-><c- n>result_ptr_</c-><c- o>-></c-><c- n>emplace</c-><c- o>&lt;</c-><c- mi>1</c-><c- o>></c-><c- p>(</c-><c- n>v</c-><c- p>),</c-> <c- n>continuation_</c-><c- p>.</c-><c- n>resume</c-><c- p>())</c-></code>.</p>
        <li data-md>
         <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>r</c-><c- p>,</c-> <c- n>e</c-><c- p>)</c-></code> is expression-equivalent to <code class="highlight"><c- p>(</c-><c- n>result_ptr_</c-><c- o>-></c-><c- n>emplace</c-><c- o>&lt;</c-><c- mi>2</c-><c- o>></c-><c- p>(</c-><i><c- n>AS_EXCEPT_PTR</c-></i><c- p>(</c-><c- n>e</c-><c- p>)),</c-> <c- n>continuation_</c-><c- p>.</c-><c- n>resume</c-><c- p>())</c-></code>, where <code class="highlight"><i><c- n>AS_EXCEPT_PTR</c-></i><c- p>(</c-><c- n>e</c-><c- p>)</c-></code> is:</p>
         <ol>
          <li data-md>
           <p><code class="highlight"><c- n>e</c-></code> if <code class="highlight"><c- n>decay_t</c-><c- o>&lt;</c-><c- n>E</c-><c- o>></c-></code> names the same type as <code class="highlight"><c- n>exception_ptr</c-></code>,</p>
          <li data-md>
           <p>Otherwise, <code class="highlight"><c- n>make_exception_ptr</c-><c- p>(</c-><c- n>system_error</c-><c- p>(</c-><c- n>e</c-><c- p>))</c-></code> if <code class="highlight"><c- n>decay_t</c-><c- o>&lt;</c-><c- n>E</c-><c- o>></c-></code> names the same type as <code class="highlight"><c- n>error_code</c-></code>,</p>
          <li data-md>
           <p>Otherwise, <code class="highlight"><c- n>make_exception_ptr</c-><c- p>(</c-><c- n>e</c-><c- p>)</c-></code>.</p>
         </ol>
        <li data-md>
         <p><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>r</c-><c- p>)</c-></code> is expression-equivalent to <code class="highlight"><c- n>continuation_</c-><c- p>.</c-><c- n>promise</c-><c- p>().</c-><c- n>unhandled_done</c-><c- p>().</c-><c- n>resume</c-><c- p>()</c-></code>.</p>
        <li data-md>
         <p><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tag_invoke</c-><c- p>(</c-><c- n>c</c-><c- p>,</c-> <c- n>r</c-><c- p>,</c-> <c- n>as</c-><c- p>...)</c-></code> is expression-equivalent to <code class="highlight"><c- n>c</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>as</c-><c- p>...)</c-></code> when the type of <code class="highlight"><c- n>c</c-></code> is not one of <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_value_t</c-></code>, <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_error_t</c-></code>, or <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done_t</c-></code>.</p>
       </ol>
      <li data-md>
       <p><b><code class="highlight"><i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>::</c-><i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i><c- p>(</c-><c- n>S</c-><c- o>&amp;&amp;</c-> <c- n>s</c-><c- p>,</c-> <c- n>P</c-><c- o>&amp;</c-> <c- n>p</c-><c- p>)</c-></code></b></p>
       <ul>
        <li data-md>
         <p><i>Effects:</i> initializes <code class="highlight"><c- n>state_</c-></code> with <code class="highlight"><c- n>connect</c-><c- p>((</c-><c- n>S</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>s</c-><c- p>,</c-> <i><c- n>awaitable</c-><c- o>-</c-><c- n>receiver</c-></i><c- p>{</c-><c- o>&amp;</c-><c- n>result_</c-><c- p>,</c-> <c- n>coroutine_handle</c-><c- o>&lt;</c-><c- n>P</c-><c- o>>::</c-><c- n>from_promise</c-><c- p>(</c-><c- n>p</c-><c- p>)})</c-></code>.</p>
       </ul>
      <li data-md>
       <p><b><code class="highlight"><c- n>value_t</c-> <i><c- n>sender</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>::</c-><c- n>await_resume</c-><c- p>()</c-></code></b></p>
       <ul>
        <li data-md>
         <p><i>Effects:</i> equivalent to:</p>
<pre class="highlight"><c- k>if</c-> <c- p>(</c-><c- n>result_</c-><c- p>.</c-><c- n>index</c-><c- p>())</c-> <c- o>==</c-> <c- mi>2</c-><c- p>)</c->
  <c- n>rethrow_exception</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>get</c-><c- o>&lt;</c-><c- mi>2</c-><c- o>></c-><c- p>(</c-><c- n>result_</c-><c- p>));</c->
<c- k>if</c-> <c- nf>constexpr</c-> <c- p>(</c-><c- o>!</c-><c- n>is_void_v</c-><c- o>&lt;</c-><c- n>value_t</c-><c- o>></c-><c- p>)</c->
  <c- k>return</c-> <c- p>(</c-><c- n>value_t</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>get</c-><c- o>&lt;</c-><c- mi>1</c-><c- o>></c-><c- p>(</c-><c- n>result_</c-><c- p>);</c->
</pre>
       </ul>
     </ol>
   </ol>
   <h4 class="heading settled" data-level="9.8.2" id="spec-execution.coro_utils.with_awaitable_senders"><span class="secno">9.8.2. </span><span class="content"><code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>with_awaitable_senders</c-></code> <b>[execution.coro_utils.with_awaitable_senders]</b></span><a class="self-link" href="#spec-execution.coro_utils.with_awaitable_senders"></a></h4>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>with_awaitable_senders</c-></code>, when used as the base class of a coroutine promise type, makes senders awaitable in that coroutine type.</p>
     <p>In addition, it provides a default implementation of <code class="highlight"><c- n>unhandled_done</c-><c- p>()</c-></code> such that if a sender completes by calling <code class="highlight"><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-></code>, it is treated as if an uncatchable "done" exception were thrown from the <i>await-expression</i>. In practice, the coroutine is never resumed, and the <code class="highlight"><c- n>unhandled_done</c-></code> of the coroutine caller’s promise type is called.</p>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>Promise</c-><c- o>></c->
  <c- k>requires</c-> <c- n>is_class_v</c-><c- o>&lt;</c-><c- n>Promise</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>same_as</c-><c- o>&lt;</c-><c- n>Promise</c-><c- p>,</c-> <c- n>remove_cvref_t</c-><c- o>&lt;</c-><c- n>Promise</c-><c- o>>></c->
  <c- k>struct</c-> <c- nc>with_awaitable_senders</c-> <c- p>{</c->
    <c- k>template</c-><c- o>&lt;</c-><c- n>OtherPromise</c-><c- o>></c->
      <c- k>requires</c-> <c- p>(</c-><c- o>!</c-><c- n>same_as</c-><c- o>&lt;</c-><c- n>OtherPromise</c-><c- p>,</c-> <c- b>void</c-><c- o>></c-><c- p>)</c->
    <c- b>void</c-> <c- n>set_continuation</c-><c- p>(</c-><c- n>coroutine_handle</c-><c- o>&lt;</c-><c- n>OtherPromise</c-><c- o>></c-> <c- n>h</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->

    <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- n>continuation</c-><c- p>()</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- n>continuation_</c-><c- p>;</c-> <c- p>}</c->

    <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- n>unhandled_done</c-><c- p>()</c-> <c- k>noexcept</c-> <c- p>{</c->
      <c- k>return</c-> <c- nf>done_handler_</c-><c- p>(</c-><c- n>continuation_</c-><c- p>.</c-><c- n>address</c-><c- p>());</c->
    <c- p>}</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Value</c-><c- o>></c->
    <i><c- n>see</c-><c- o>-</c-><c- n>below</c-></i> <c- n>await_transform</c-><c- p>(</c-><c- n>Value</c-><c- o>&amp;&amp;</c-> <c- n>value</c-><c- p>);</c->

   <c- k>private</c-><c- o>:</c->
    <c- c1>// exposition only</c->
    <c- p>[[</c-><c- n>noreturn</c-><c- p>]]</c-> <c- k>static</c-> <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- n>default_unhandled_done</c-><c- p>(</c-><c- b>void</c-><c- o>*</c-><c- p>)</c-> <c- k>noexcept</c-> <c- p>{</c->
      <c- n>terminate</c-><c- p>();</c->
    <c- p>}</c->
    <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- n>continuation_</c-><c- p>{};</c-> <c- c1>// exposition only</c->
    <c- c1>// exposition only</c->
    <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- p>(</c-><c- o>*</c-><c- n>done_handler_</c-><c- p>)(</c-><c- b>void</c-><c- o>*</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>=</c-> <c- o>&amp;</c-><c- n>default_unhandled_done</c-><c- p>;</c->
  <c- p>};</c->
</pre>
    <li data-md>
     <p><b><code class="highlight"><c- b>void</c-> <c- n>set_continuation</c-><c- p>(</c-><c- n>coroutine_handle</c-><c- o>&lt;</c-><c- n>OtherPromise</c-><c- o>></c-> <c- n>h</c-><c- p>)</c-> <c- k>noexcept</c-></code></b></p>
     <ul>
      <li data-md>
       <p><i>Effects:</i> equivalent to:</p>
<pre class="highlight"><c- n>continuation_</c-> <c- o>=</c-> <c- n>h</c-><c- p>;</c->
<c- k>if</c-> <c- nf>constexpr</c-> <c- p>(</c-> <c- k>requires</c-><c- p>(</c-><c- n>OtherPromise</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- p>{</c-> <c- n>other</c-><c- p>.</c-><c- n>unhandled_done</c-><c- p>();</c-> <c- p>}</c-> <c- p>)</c-> <c- p>{</c->
  <c- n>done_handler_</c-> <c- o>=</c-> <c- p>[](</c-><c- b>void</c-><c- o>*</c-> <c- n>p</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>-></c-> <c- n>coroutine_handle</c-><c- o>&lt;></c-> <c- p>{</c->
    <c- k>return</c-> <c- n>coroutine_handle</c-><c- o>&lt;</c-><c- n>OtherPromise</c-><c- o>>::</c-><c- n>from_address</c-><c- p>(</c-><c- n>p</c-><c- p>)</c->
      <c- p>.</c-><c- n>promise</c-><c- p>().</c-><c- n>unhandled_done</c-><c- p>();</c->
  <c- p>};</c->
<c- p>}</c-> <c- k>else</c-> <c- p>{</c->
  <c- n>done_handler_</c-> <c- o>=</c-> <c- n>default_unhandled_done</c-><c- p>;</c->
<c- p>}</c->
</pre>
     </ul>
    <li data-md>
     <p><b><code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- k>auto</c-><c- p>)</c-> <c- n>await_transform</c-><c- p>(</c-><c- n>Value</c-><c- o>&amp;&amp;</c-> <c- n>value</c-><c- p>)</c-></code></b></p>
     <ul>
      <li data-md>
       <p><i>Effects:</i> equivalent to:</p>
<pre class="highlight"><c- k>if</c-> <c- nf>constexpr</c-> <c- p>(</c-><i><c- n>is</c-><c- o>-</c-><c- n>awaitable</c-></i><c- o>&lt;</c-><c- n>Value</c-><c- o>></c-><c- p>)</c->
  <c- k>return</c-> <c- p>(</c-><c- n>Value</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>value</c-><c- p>;</c->
<c- k>else</c-> <c- k>if</c-> <c- k>constexpr</c-> <c- p>(</c-><i><c- n>single</c-><c- o>-</c-><c- n>typed</c-><c- o>-</c-><c- n>sender</c-></i><c- o>&lt;</c-><c- n>Value</c-><c- o>></c-><c- p>)</c->
  <c- k>return</c-> <c- n>as_awaitable</c-><c- p>(</c-><c- k>static_cast</c-><c- o>&lt;</c-><c- n>Value</c-><c- o>&amp;&amp;></c-><c- p>(</c-><c- n>value</c-><c- p>),</c-> <c- k>static_cast</c-><c- o>&lt;</c-><c- n>Promise</c-><c- o>&amp;></c-><c- p>(</c-><c- o>*</c-><c- k>this</c-><c- p>));</c->
<c- k>else</c->
  <c- nf>return</c-> <c- p>(</c-><c- n>Value</c-><c- o>&amp;&amp;</c-><c- p>)</c-> <c- n>value</c-><c- p>;</c->
</pre>
     </ul>
   </ol>
   <h2 class="heading settled" id="appendix-a-cancellation-examples"><span class="content">Appendix A - Cancellation Examples</span><a class="self-link" href="#appendix-a-cancellation-examples"></a></h2>
   <h3 class="heading settled" id="appendix-a-async_recv"><span class="content">Cancellation Example: Socket <code class="highlight"><c- n>async_recv</c-><c- p>()</c-></code> #</span><a class="self-link" href="#appendix-a-async_recv"></a></h3>
   <p>To get a better feel for how this interface might be used by low-level operations see this example implementation
of a cancellable <code class="highlight"><c- n>async_recv</c-><c- p>()</c-></code> operation for a Windows Socket.</p>
<pre class="language-c++ highlight"><c- k>struct</c-> <c- nc>operation_base</c-> <c- o>:</c-> <c- n>WSAOVERALAPPED</c-> <c- p>{</c->
    <c- n>using</c-> <c- n>completion_fn</c-> <c- o>=</c-> <c- b>void</c-><c- p>(</c-><c- n>operation_base</c-><c- o>*</c-> <c- n>op</c-><c- p>,</c-> <c- n>DWORD</c-> <c- n>bytesTransferred</c-><c- p>,</c-> <c- b>int</c-> <c- n>errorCode</c-><c- p>)</c-> <c- n>noexcept</c-><c- p>;</c->

    <c- c1>// Assume IOCP event loop will call this when this OVERLAPPED structure is dequeued.</c->
    <c- n>completion_fn</c-><c- o>*</c-> <c- n>completed</c-><c- p>;</c->
<c- p>};</c->

<c- n>template</c-><c- o>&lt;</c-><c- n>typename</c-> <c- n>Receiver</c-><c- o>></c->
<c- k>struct</c-> <c- nc>recv_op</c-> <c- o>:</c-> <c- n>operation_base</c-> <c- p>{</c->
    <c- n>recv_op</c-><c- p>(</c-><c- n>SOCKET</c-> <c- n>s</c-><c- p>,</c-> <c- b>void</c-><c- o>*</c-> <c- n>data</c-><c- p>,</c-> <c- b>size_t</c-> <c- n>len</c-><c- p>,</c-> <c- n>Receiver</c-> <c- n>r</c-><c- p>)</c->
    <c- o>:</c-> <c- n>receiver</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>r</c-><c- p>))</c->
    <c- p>,</c-> <c- n>sock</c-><c- p>(</c-><c- n>s</c-><c- p>)</c-> <c- p>{</c->
        <c- n>this</c-><c- o>-></c-><c- n>Internal</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- n>this</c-><c- o>-></c-><c- n>InternalHigh</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- n>this</c-><c- o>-></c-><c- n>Offset</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- n>this</c-><c- o>-></c-><c- n>OffsetHigh</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- n>this</c-><c- o>-></c-><c- n>hEvent</c-> <c- o>=</c-> NULL<c- p>;</c->
        <c- n>this</c-><c- o>-></c-><c- n>completed</c-> <c- o>=</c-> <c- o>&amp;</c-><c- n>recv_op</c-><c- o>::</c-><c- n>on_complete</c-><c- p>;</c->
        <c- n>buffer</c-><c- p>.</c-><c- n>len</c-> <c- o>=</c-> <c- n>len</c-><c- p>;</c->
        <c- n>buffer</c-><c- p>.</c-><c- n>buf</c-> <c- o>=</c-> <c- n>static_cast</c-><c- o>&lt;</c-><c- n>CHAR</c-><c- o>*></c-><c- p>(</c-><c- n>data</c-><c- p>);</c->
    <c- p>}</c->

    <c- n>friend</c-> <c- b>void</c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>tag_t</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>start</c-><c- o>></c-><c- p>,</c-> <c- n>recv_op</c-><c- o>&amp;</c-> <c- n>self</c-><c- p>)</c-> <c- n>noexcept</c-> <c- p>{</c->
        <c- c1>// Avoid even calling WSARecv() if operation already cancelled</c->
        <c- k>auto</c-> <c- n>st</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>get_stop_token</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>);</c->
        <c- k>if</c-> <c- p>(</c-><c- n>st</c-><c- p>.</c-><c- n>stop_requested</c-><c- p>())</c-> <c- p>{</c->
            <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>));</c->
            <c- k>return</c-><c- p>;</c->
        <c- p>}</c->

        <c- c1>// Store and cache result here in case it changes during execution</c->
        <c- k>const</c-> <c- b>bool</c-> <c- n>stopPossible</c-> <c- o>=</c-> <c- n>st</c-><c- p>.</c-><c- n>stop_possible</c-><c- p>();</c->
        <c- k>if</c-> <c- p>(</c-><c- o>!</c-><c- n>stopPossible</c-><c- p>)</c-> <c- p>{</c->
            <c- n>self</c-><c- p>.</c-><c- n>ready</c-><c- p>.</c-><c- n>store</c-><c- p>(</c->true<c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_relaxed</c-><c- p>);</c->
        <c- p>}</c->

        <c- c1>// Launch the operation</c->
        <c- n>DWORD</c-> <c- n>bytesTransferred</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- n>DWORD</c-> <c- n>flags</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
        <c- b>int</c-> <c- n>result</c-> <c- o>=</c-> <c- n>WSARecv</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>sock</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>self</c-><c- p>.</c-><c- n>buffer</c-><c- p>,</c-> <c- mi>1</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>bytesTransferred</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>flags</c-><c- p>,</c->
                             <c- n>static_cast</c-><c- o>&lt;</c-><c- n>WSAOVERLAPPED</c-><c- o>*></c-><c- p>(</c-><c- o>&amp;</c-><c- n>self</c-><c- p>),</c-> NULL<c- p>);</c->
        <c- k>if</c-> <c- p>(</c-><c- n>result</c-> <c- o>==</c-> <c- n>SOCKET_ERROR</c-><c- p>)</c-> <c- p>{</c->
            <c- b>int</c-> <c- n>errorCode</c-> <c- o>=</c-> <c- n>WSAGetLastError</c-><c- p>();</c->
            <c- k>if</c-> <c- p>(</c-><c- n>errorCode</c-> <c- o>!=</c-> <c- n>WSA_IO_PENDING</c-><c- p>))</c-> <c- p>{</c->
                <c- k>if</c-> <c- p>(</c-><c- n>errorCode</c-> <c- o>==</c-> <c- n>WSA_OPERATION_ABORTED</c-><c- p>)</c-> <c- p>{</c->
                    <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_done</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>));</c->
                <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
                    <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>),</c->
                                              <c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- p>(</c-><c- n>errorCode</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>system_category</c-><c- p>()));</c->
                <c- p>}</c->
                <c- k>return</c-><c- p>;</c->
            <c- p>}</c->
        <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
            <c- c1>// Completed synchronously (assuming FILE_SKIP_COMPLETION_PORT_ON_SUCCESS has been set)</c->
            <c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>),</c-> <c- n>bytesTransferred</c-><c- p>);</c->
            <c- k>return</c-><c- p>;</c->
        <c- p>}</c->

        <c- c1>// If we get here then operation has launched successfully and will complete asynchronously.</c->
        <c- c1>// May be completing concurrently on another thread already.</c->
        <c- k>if</c-> <c- p>(</c-><c- n>stopPossible</c-><c- p>)</c-> <c- p>{</c->
            <c- c1>// Register the stop callback</c->
            <c- n>self</c-><c- p>.</c-><c- n>stopCallback</c-><c- p>.</c-><c- n>emplace</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>st</c-><c- p>),</c-> <c- n>cancel_cb</c-><c- p>{</c-><c- n>self</c-><c- p>});</c->

            <c- c1>// Mark as 'completed'</c->
            <c- k>if</c-> <c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>ready</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>)</c-> <c- o>||</c->
                <c- n>self</c-><c- p>.</c-><c- n>ready</c-><c- p>.</c-><c- n>exchange</c-><c- p>(</c->true<c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_acq_rel</c-><c- p>))</c-> <c- p>{</c->
                <c- c1>// Already completed on another thread</c->
                <c- n>self</c-><c- p>.</c-><c- n>stopCallback</c-><c- p>.</c-><c- n>reset</c-><c- p>();</c->

                <c- n>BOOL</c-> <c- n>ok</c-> <c- o>=</c-> <c- n>WSAGetOverlappedResult</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>sock</c-><c- p>,</c-> <c- p>(</c-><c- n>WSAOVERLAPPED</c-><c- o>*</c-><c- p>)</c-><c- o>&amp;</c-><c- n>self</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>bytesTransferred</c-><c- p>,</c-> <c- n>FALSE</c-><c- p>,</c-> <c- o>&amp;</c-><c- n>flags</c-><c- p>);</c->
                <c- k>if</c-> <c- p>(</c-><c- n>ok</c-><c- p>)</c-> <c- p>{</c->
                    <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>),</c-> <c- n>bytesTransferred</c-><c- p>);</c->
                <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
                    <c- b>int</c-> <c- n>errorCode</c-> <c- o>=</c-> <c- n>WSAGetLastError</c-><c- p>();</c->
                    <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>self</c-><c- p>.</c-><c- n>receiver</c-><c- p>),</c->
                                              <c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- p>(</c-><c- n>errorCode</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>system_category</c-><c- p>()));</c->
                <c- p>}</c->
            <c- p>}</c->
        <c- p>}</c->
    <c- p>}</c->

    <c- k>struct</c-> <c- nc>cancel_cb</c-> <c- p>{</c->
        <c- n>recv_op</c-><c- o>&amp;</c-> <c- n>op</c-><c- p>;</c->

        <c- b>void</c-> <c- nf>operator</c-><c- p>()()</c-> <c- n>noexcept</c-> <c- p>{</c->
            <c- n>CancelIoEx</c-><c- p>((</c-><c- n>HANDLE</c-><c- p>)</c-><c- n>op</c-><c- p>.</c-><c- n>sock</c-><c- p>,</c-> <c- p>(</c-><c- n>OVERLAPPED</c-><c- o>*</c-><c- p>)(</c-><c- n>WSAOVERLAPPED</c-><c- o>*</c-><c- p>)</c-><c- o>&amp;</c-><c- n>op</c-><c- p>);</c->
        <c- p>}</c->
    <c- p>};</c->

    <c- k>static</c-> <c- b>void</c-> <c- n>on_complete</c-><c- p>(</c-><c- n>operation_base</c-><c- o>*</c-> <c- n>op</c-><c- p>,</c-> <c- n>DWORD</c-> <c- n>bytesTransferred</c-><c- p>,</c-> <c- b>int</c-> <c- n>errorCode</c-><c- p>)</c-> <c- n>noexcept</c-> <c- p>{</c->
        <c- n>recv_op</c-><c- o>&amp;</c-> <c- n>self</c-> <c- o>=</c-> <c- o>*</c-><c- n>static_cast</c-><c- o>&lt;</c-><c- n>recv_op</c-><c- o>*></c-><c- p>(</c-><c- n>op</c-><c- p>);</c->

        <c- k>if</c-> <c- p>(</c-><c- n>ready</c-><c- p>.</c-><c- n>load</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>memory_order_acquire</c-><c- p>)</c-> <c- o>||</c-> <c- n>ready</c-><c- p>.</c-><c- n>exchange</c-><c- p>(</c->true<c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>memory_order_acq_rel</c-><c- p>))</c-> <c- p>{</c->
            <c- c1>// Unsubscribe any stop-callback so we know that CancelIoEx() is not accessing 'op' any more</c->
            <c- n>stopCallback</c-><c- p>.</c-><c- n>reset</c-><c- p>();</c->

            <c- k>if</c-> <c- p>(</c-><c- n>errorCode</c-> <c- o>==</c-> <c- mi>0</c-><c- p>)</c-> <c- p>{</c->
                <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_value</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>receiver</c-><c- p>),</c-> <c- n>bytesTransferred</c-><c- p>);</c->
            <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
                <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>set_error</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>receiver</c-><c- p>),</c->
                                          <c- n>std</c-><c- o>::</c-><c- n>error_code</c-><c- p>(</c-><c- n>errorCode</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>system_category</c-><c- p>()));</c->
            <c- p>}</c->
        <c- p>}</c->
    <c- p>}</c->

    <c- n>Receiver</c-> <c- n>receiver</c-><c- p>;</c->
    <c- n>SOCKET</c-> <c- n>sock</c-><c- p>;</c->
    <c- n>WSABUF</c-> <c- n>buffer</c-><c- p>;</c->
    <c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>typename</c-> <c- n>stop_callback_type_t</c-><c- o>&lt;</c-><c- n>Receiver</c-><c- o>>::</c-><c- n>template</c-> <c- n>callback_type</c-><c- o>&lt;</c-><c- n>cancel_cb</c-><c- o>>></c-> <c- n>stopCallback</c-><c- p>;</c->
    <c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>bool</c-><c- o>></c-> <c- n>ready</c-><c- p>{</c->false<c- p>};</c->
<c- p>};</c->

<c- k>struct</c-> <c- nc>recv_sender</c-> <c- p>{</c->
    <c- n>SOCKET</c-> <c- n>sock</c-><c- p>;</c->
    <c- b>void</c-><c- o>*</c-> <c- n>data</c-><c- p>;</c->
    <c- b>size_t</c-> <c- n>len</c-><c- p>;</c->

    <c- n>template</c-><c- o>&lt;</c-><c- n>typename</c-> <c- n>Receiver</c-><c- o>></c->
    <c- n>friend</c-> <c- n>recv_op</c-><c- o>&lt;</c-><c- n>Receiver</c-><c- o>></c-> <c- n>tag_invoke</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>tag_t</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>connect</c-><c- o>></c->
                                        <c- k>const</c-> <c- n>recv_sender</c-><c- o>&amp;</c-> <c- n>s</c-><c- p>,</c->
                                        <c- n>Receiver</c-> <c- n>r</c-><c- p>)</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>recv_op</c-><c- o>&lt;</c-><c- n>Receiver</c-><c- o>></c-><c- p>{</c-><c- n>s</c-><c- p>.</c-><c- n>sock</c-><c- p>,</c-> <c- n>s</c-><c- p>.</c-><c- n>data</c-><c- p>,</c-> <c- n>s</c-><c- p>.</c-><c- n>len</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>r</c-><c- p>)};</c->
    <c- p>}</c->
<c- p>};</c->

<c- n>recv_sender</c-> <c- nf>async_recv</c-><c- p>(</c-><c- n>SOCKET</c-> <c- n>s</c-><c- p>,</c-> <c- b>void</c-><c- o>*</c-> <c- n>data</c-><c- p>,</c-> <c- b>size_t</c-> <c- n>len</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>recv_sender</c-><c- p>{</c-><c- n>s</c-><c- p>,</c-> <c- n>data</c-><c- p>,</c-> <c- n>len</c-><c- p>};</c->
<c- p>}</c->
</pre>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don’t scroll to compensate for the ToC if we’re above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don’t know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn’t exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn’t standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don’t have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we’re at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can’t find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
  <h2 class="no-num no-ref heading settled" id="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2>
  <h3 class="no-num no-ref heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3>
  <ul class="index">
   <li><a href="#algorithm">algorithm</a><span>, in § 3.2</span>
   <li><a href="#completion-schedulers">completion schedulers</a><span>, in § 4.5</span>
   <li><a href="#connect">connect</a><span>, in § 5.3</span>
   <li><a href="#execution-context">execution context</a><span>, in § 4.1</span>
   <li><a href="#multi-shot-sender">multi-shot sender</a><span>, in § 4.7</span>
   <li><a href="#operation-state">operation state</a><span>, in § 5.2</span>
   <li><a href="#pipeable">pipeable</a><span>, in § 4.12</span>
   <li><a href="#piped">piped</a><span>, in § 4.12</span>
   <li><a href="#query">query</a><span>, in § 3.2</span>
   <li><a href="#receiver">receiver</a><span>, in § 5.1</span>
   <li><a href="#receiver-contract">receiver contract</a><span>, in § 5.1</span>
   <li><a href="#scheduler">scheduler</a><span>, in § 4.2</span>
   <li><a href="#send">send</a><span>, in § 4.3</span>
   <li><a href="#sender">sender</a><span>, in § 4.3</span>
   <li><a href="#sender-adaptor">sender adaptor</a><span>, in § 4.20</span>
   <li><a href="#sender-algorithms">sender algorithms</a><span>, in § 4.4</span>
   <li><a href="#sender-consumer">sender consumer</a><span>, in § 4.21</span>
   <li><a href="#sender-factory">sender factory</a><span>, in § 4.19</span>
   <li><a href="#single-shot-sender">single-shot sender</a><span>, in § 4.7</span>
   <li><a href="#start">start</a><span>, in § 4.20</span>
   <li><a href="#strictly-lazy-submission">Strictly lazy submission</a><span>, in § 5.5</span>
  </ul>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-n4885">[N4885]
   <dd>Thomas Köppe. <a href="https://wg21.link/n4885"><cite>Working Draft, Standard for Programming Language C++</cite></a>. 17 March 2021. URL: <a href="https://wg21.link/n4885">https://wg21.link/n4885</a>
   <dt id="biblio-p0443r14">[P0443R14]
   <dd>Jared Hoberock, Michael Garland, Chris Kohlhoff, Chris Mysen, H. Carter Edwards, Gordon Brown, D. S. Hollman. <a href="https://wg21.link/p0443r14"><cite>A Unified Executors Proposal for C++</cite></a>. 15 September 2020. URL: <a href="https://wg21.link/p0443r14">https://wg21.link/p0443r14</a>
   <dt id="biblio-p0981r0">[P0981R0]
   <dd>Richard Smith, Gor Nishanov. <a href="https://wg21.link/p0981r0"><cite>Halo: coroutine Heap Allocation eLision Optimization: the joint response</cite></a>. 18 March 2018. URL: <a href="https://wg21.link/p0981r0">https://wg21.link/p0981r0</a>
   <dt id="biblio-p1056r1">[P1056R1]
   <dd>Lewis Baker, Gor Nishanov. <a href="https://wg21.link/p1056r1"><cite>Add lazy coroutine (coroutine task) type</cite></a>. 7 October 2018. URL: <a href="https://wg21.link/p1056r1">https://wg21.link/p1056r1</a>
   <dt id="biblio-p1895r0">[P1895R0]
   <dd>Lewis Baker, Eric Niebler, Kirk Shoop. <a href="https://wg21.link/p1895r0"><cite>tag_invoke: A general pattern for supporting customisable functions</cite></a>. 8 October 2019. URL: <a href="https://wg21.link/p1895r0">https://wg21.link/p1895r0</a>
   <dt id="biblio-p1897r3">[P1897R3]
   <dd>Lee Howes. <a href="https://wg21.link/p1897r3"><cite>Towards C++23 executors: A proposal for an initial set of algorithms</cite></a>. 16 May 2020. URL: <a href="https://wg21.link/p1897r3">https://wg21.link/p1897r3</a>
   <dt id="biblio-p2175r0">[P2175R0]
   <dd>Lewis Baker. <a href="https://wg21.link/p2175r0"><cite>Composable cancellation for sender-based async operations</cite></a>. 15 December 2020. URL: <a href="https://wg21.link/p2175r0">https://wg21.link/p2175r0</a>
  </dl>
  <aside class="dfn-panel" data-for="algorithm">
   <b><a href="#algorithm">#algorithm</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-algorithm">4.19. User-facing sender factories</a>
    <li><a href="#ref-for-algorithm①">4.20. User-facing sender adaptors</a>
    <li><a href="#ref-for-algorithm②">4.21. User-facing sender consumers</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="send">
   <b><a href="#send">#send</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-send">4.5.1. execution::get_completion_scheduler</a>
    <li><a href="#ref-for-send①">4.9. Senders are joinable</a>
    <li><a href="#ref-for-send②">4.19.2. execution::just</a>
    <li><a href="#ref-for-send③">4.19.3. execution::transfer_just</a>
    <li><a href="#ref-for-send④">4.20.2. execution::then</a>
    <li><a href="#ref-for-send⑤">4.20.4. execution::let_*</a>
    <li><a href="#ref-for-send⑥">5.8. Most senders are typed</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="sender-algorithms">
   <b><a href="#sender-algorithms">#sender-algorithms</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-sender-algorithms">4.3. Senders describe work</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="completion-schedulers">
   <b><a href="#completion-schedulers">#completion-schedulers</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-completion-schedulers">4.5.1. execution::get_completion_scheduler</a>
    <li><a href="#ref-for-completion-schedulers①">4.6. Execution context transitions are explicit</a>
    <li><a href="#ref-for-completion-schedulers②">4.9. Senders are joinable</a>
    <li><a href="#ref-for-completion-schedulers③">4.19.2. execution::just</a>
    <li><a href="#ref-for-completion-schedulers④">4.19.3. execution::transfer_just</a>
    <li><a href="#ref-for-completion-schedulers⑤">4.19.4. execution::just_error</a>
    <li><a href="#ref-for-completion-schedulers⑥">4.19.5. execution::just_done</a>
    <li><a href="#ref-for-completion-schedulers⑦">4.20.5. execution::on</a>
    <li><a href="#ref-for-completion-schedulers⑧">4.20.11. execution::when_all</a>
    <li><a href="#ref-for-completion-schedulers⑨">4.20.12. execution::transfer_when_all</a>
    <li><a href="#ref-for-completion-schedulers①⓪">5.4. Sender algorithms are customizable</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="sender-factory">
   <b><a href="#sender-factory">#sender-factory</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-sender-factory">4.4. Senders are composable through sender algorithms</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="sender-adaptor">
   <b><a href="#sender-adaptor">#sender-adaptor</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-sender-adaptor">4.4. Senders are composable through sender algorithms</a>
    <li><a href="#ref-for-sender-adaptor①">5.4. Sender algorithms are customizable</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="sender-consumer">
   <b><a href="#sender-consumer">#sender-consumer</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-sender-consumer">4.4. Senders are composable through sender algorithms</a>
    <li><a href="#ref-for-sender-consumer①">5.4. Sender algorithms are customizable</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="receiver-contract">
   <b><a href="#receiver-contract">#receiver-contract</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-receiver-contract">5.3. execution::connect</a>
   </ul>
  </aside>
  <aside class="dfn-panel" data-for="connect">
   <b><a href="#connect">#connect</a></b><b>Referenced in:</b>
   <ul>
    <li><a href="#ref-for-connect">4.20.13. execution::ensure_started</a>
   </ul>
  </aside>
<script>/* script-dfn-panel */

document.body.addEventListener("click", function(e) {
    var queryAll = function(sel) { return [].slice.call(document.querySelectorAll(sel)); }
    // Find the dfn element or panel, if any, that was clicked on.
    var el = e.target;
    var target;
    var hitALink = false;
    while(el.parentElement) {
        if(el.tagName == "A") {
            // Clicking on a link in a <dfn> shouldn't summon the panel
            hitALink = true;
        }
        if(el.classList.contains("dfn-paneled")) {
            target = "dfn";
            break;
        }
        if(el.classList.contains("dfn-panel")) {
            target = "dfn-panel";
            break;
        }
        el = el.parentElement;
    }
    if(target != "dfn-panel") {
        // Turn off any currently "on" or "activated" panels.
        queryAll(".dfn-panel.on, .dfn-panel.activated").forEach(function(el){
            el.classList.remove("on");
            el.classList.remove("activated");
        });
    }
    if(target == "dfn" && !hitALink) {
        // open the panel
        var dfnPanel = document.querySelector(".dfn-panel[data-for='" + el.id + "']");
        if(dfnPanel) {
            dfnPanel.classList.add("on");
            var rect = el.getBoundingClientRect();
            dfnPanel.style.left = window.scrollX + rect.right + 5 + "px";
            dfnPanel.style.top = window.scrollY + rect.top + "px";
            var panelRect = dfnPanel.getBoundingClientRect();
            var panelWidth = panelRect.right - panelRect.left;
            if(panelRect.right > document.body.scrollWidth && (rect.left - (panelWidth + 5)) > 0) {
                // Reposition, because the panel is overflowing
                dfnPanel.style.left = window.scrollX + rect.left - (panelWidth + 5) + "px";
            }
        } else {
            console.log("Couldn't find .dfn-panel[data-for='" + el.id + "']");
        }
    } else if(target == "dfn-panel") {
        // Switch it to "activated" state, which pins it.
        el.classList.add("activated");
        el.style.left = null;
        el.style.top = null;
    }

});
</script>