<!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>P2183R0: Executors Review: Properties</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
 *
 * 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)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * 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
 *
 * 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)
 *
 ******************************************************************************/

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

	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;

		/* Colors */
		color: black;
		background: white 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-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		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;
		border-color: #c00;
	}

	/* 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: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

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

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* 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-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** 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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}
		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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}

		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;
		background: transparent;
	}

	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,
	#subtitle {
		/* #subtitle 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) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		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;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; 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: medium;
	}
	dfn var {
		font-style: normal;
	}

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

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** 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;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	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;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

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

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

	img {
		border-style: none;
	}

	/* 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;
	}
	.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 {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

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

	blockquote {
		border-color: silver;
	}

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

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* 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;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* 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;
		background: #E9FBE9;
		overflow: auto;
	}

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

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

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

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

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

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** 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: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

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

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

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

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    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;
	}

	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-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;
		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;
		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-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.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;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* 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 .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @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 {
			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; }
		}
	/* } */

	@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 {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			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 {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** 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]) {
		background: #f7f8f9;
	}

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

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

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

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             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 table positioning:
		   "content column" is 50ems wide at max; less on smaller screens.
		   Extra space (after ToC + content) is empty on the right.

		   1. When table < content column, centers table in column.
		   2. When content < table < available, left-aligns.
		   3. When table > 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 40de15f9, updated Thu Jun 11 17:47:04 2020 -0700" name="generator">
  <link href="http://wg21.link/p2183r0" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<style>
.ins, ins, ins *, span.ins, span.ins * {
  background-color: rgb(200, 250, 200);
  color: rgb(0, 136, 0);
  text-decoration: underline;
}
.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);
}
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: #005a9c;
    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-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-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 */

.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: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

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

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
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>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P2183R0<br>Executors Review: Properties</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2020-07-14">2020-07-14</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="http://wg21.link/p2183r0">http://wg21.link/p2183r0</a>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:dolsen@nvidia.com">David Olsen</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:ruslan.arutyunyan@intel.com">Ruslan Arutyunyan</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:michaelj.voss@intel.com">Michael J. Voss</a>
     <dd>
      <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>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:chris@kohlhoff.com">Chris Kohlhoff</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:dshollman@sandia.gov">D.S. Hollman</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:kirkshoop@fb.com">Kirk Shoop</a>
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:sinbal2l@gmail.com">Inbal Levi</a>
     <dt>Audience:
     <dd>LEWG
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
    </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="#scope"><span class="secno">1</span> <span class="content">Scope</span></a>
    <li><a href="#intro"><span class="secno">2</span> <span class="content">Introduction</span></a>
    <li>
     <a href="#examples"><span class="secno">3</span> <span class="content">Examples</span></a>
     <ol class="toc">
      <li>
       <a href="#examples-std-prop"><span class="secno">3.1</span> <span class="content">Using standard properties</span></a>
       <ol class="toc">
        <li><a href="#examples-custom-exec"><span class="secno">3.1.1</span> <span class="content">Writing a custom executor</span></a>
        <li><a href="#examples-any-executor"><span class="secno">3.1.2</span> <span class="content">Using <code class="highlight"><c- n>any_executor</c-></code></span></a>
       </ol>
      <li>
       <a href="#examples-custom"><span class="secno">3.2</span> <span class="content">Using custom properties</span></a>
       <ol class="toc">
        <li><a href="#examples-custom-custom"><span class="secno">3.2.1</span> <span class="content">Modifying our custom executor</span></a>
        <li><a href="#examples-custom-any-executor"><span class="secno">3.2.2</span> <span class="content">Using <code class="highlight"><c- n>any_executor</c-></code> again</span></a>
       </ol>
     </ol>
    <li><a href="#wording-bugs"><span class="secno">4</span> <span class="content">Small Issues</span></a>
    <li>
     <a href="#issues"><span class="secno">5</span> <span class="content">Issues</span></a>
     <ol class="toc">
      <li><a href="#applicability"><span class="secno">5.1</span> <span class="content">Should properties be usable with non-executors?</span></a>
      <li><a href="#blocking"><span class="secno">5.2</span> <span class="content">Generic blocking adapter is not implementable</span></a>
      <li><a href="#movability"><span class="secno">5.3</span> <span class="content">Non-movable properties</span></a>
      <li><a href="#prefer"><span class="secno">5.4</span> <span class="content">Polymorphic executor wrappers and prefer-only properties</span></a>
      <li><a href="#find-prop"><span class="secno">5.5</span> <span class="content"><code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-></code></span></a>
      <li><a href="#any-executor-target"><span class="secno">5.6</span> <span class="content"><code class="highlight"><c- n>any_executor</c-><c- o>&lt;</c-><c- n>P</c-><c- p>...</c-><c- o>>::</c-><c- n>target</c-></code> causes unused RTTI overhead</span></a>
      <li><a href="#bulk_guarantee"><span class="secno">5.7</span> <span class="content"><code class="highlight"><c- n>bulk_guarantee</c-></code> specification should match execution policies</span></a>
      <li><a href="#established"><span class="secno">5.8</span> <span class="content">What does "established property" mean?</span></a>
      <li><a href="#allocator-value"><span class="secno">5.9</span> <span class="content"><code class="highlight"><c- n>allocator_t</c-><c- o>::</c-><c- n>value</c-></code> should not be static</span></a>
      <li><a href="#context"><span class="secno">5.10</span> <span class="content"><code class="highlight"><c- n>context</c-></code> property has no constraints</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="scope"><span class="secno">1. </span><span class="content">Scope</span><a class="self-link" href="#scope"></a></h2>
   <p>We were asked by the chair of LEWG to review how the Executors proposal <a data-link-type="biblio" href="#biblio-p0443r13">[P0443R13]</a> makes use of Properties <a data-link-type="biblio" href="#biblio-p1393">[P1393]</a>.  We were to look at all uses of properties within P0443, not just the sections that define properties.</p>
   <p>We did not review P1393, where the properties mechanism is defined.  But we did spend a fair amount of time reading and understanding P1393, and in the process we noticed a couple of issues in that paper, and we have offered suggested fixes.</p>
   <p>The review team varied some during the effort, but ended up consisting of David Olsen, Ruslan Arutyunyan, Michael J. Voss, and Michał Dominiak, with contributions from the polymorphic executor review team led by Inbal Levi.  Michael and Ruslan wrote all the examples.  We were assisted in all our efforts by three of the many authors of P0443, Chris Kohlhoff, Daisy Hollman, and Kirk Shoop.  The authors answered many questions, provided lots of background information, made useful suggestions, and were generally very helpful.  In particular, Chris Kohlhoff’s implementation of the properties mechanism and some other parts of executors that are part of <a data-link-type="biblio" href="#biblio-asio">[Asio]</a> (see also <a href="https://sourceforge.net/projects/asio/files/asio/1.17.0 %28Development%29/">here</a> and <a href="https://think-async.com/Asio/asio-1.17.0/doc/">here</a>) made it much easier to write sample code and try out ideas.</p>
   <h2 class="heading settled" data-level="2" id="intro"><span class="secno">2. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   <p>Properties were originally suggested as a way to simplify the configuration and customization of the <code class="highlight"><c- n>execute</c-></code> function for executors.  At one time during the development of P0443, there were more than a dozen proposed execution functions or customization points, but even that large set covered only a subset of the different ways that execution could happen.  The properties mechanism was developed to avoid this explosion in execution functions.  Each characteristic of execution was separated into its own property, allowing for independent configuration of that characteristic.  The properties mechanism (along with senders/receivers for configuration of returning results) reduced the number of execution functions down to two, <code class="highlight"><c- n>execute</c-></code> and <code class="highlight"><c- n>bulk_execution</c-></code>.  The development of properties is explained in more detail in <a data-link-type="biblio" href="#biblio-p2033">[P2033]</a>.</p>
   <p>The properties mechanism was deemed to be useful beyond executors, so it was separated into its own paper, <a data-link-type="biblio" href="#biblio-p1393">[P1393]</a>, and moved from namespace <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execute</c-></code> to namespace <code class="highlight"><c- n>std</c-></code>.  Properties are not used by the standard library outside of executors at the moment, but that is a possible future direction.  A good introduction to properties in general, not specific to executors, is available in Chris’s YouTube <a href="https://youtu.be/Fp8DuVWesT4">video</a>.</p>
   <h2 class="heading settled" data-level="3" id="examples"><span class="secno">3. </span><span class="content">Examples</span><a class="self-link" href="#examples"></a></h2>
   <p>We provide a set of examples that begin with a simple use of a standard property and standard executor. We then introduce a custom executor and show how support for a standard property can be added to that executor. We next implement a custom property and show how it can be used with a standard executor as well as our custom executor. Throughout the discussion we also provide example uses of <code class="highlight"><c- n>any_executor</c-></code> that wrap both the standard and custom executor and use both standard and custom properties.</p>
   <p>All of the examples were compiled against the <a data-link-type="biblio" href="#biblio-asio">[Asio]</a> implementation of executors, so the code refers to many things in the <code class="highlight"><c- n>asio</c-></code> namespace.  Simply changing <code class="highlight"><c- n>asio</c-></code> to <code class="highlight"><c- n>std</c-></code> should result in standard-conforming code.</p>
   <h3 class="heading settled" data-level="3.1" id="examples-std-prop"><span class="secno">3.1. </span><span class="content">Using standard properties</span><a class="self-link" href="#examples-std-prop"></a></h3>
   <p>The example that follows shows a simple use of <code class="highlight"><c- n>blocking_t</c-></code> with the executor returned from <code class="highlight"><c- n>static_thread_pool</c-></code>. Our example has a race on the variable <code class="highlight"><c- n>i</c-></code> if the function objects passed to <code class="highlight"><c- n>execute</c-></code> execute concurrently -- this is intentional. We include this race purely to introduce an easily demonstrated effect of changing the blocking property; it is not expected that <code class="highlight"><c- n>blocking_t</c-></code> will be used to avoid races in real applications.</p>
<pre class="highlight"><c- b>void</c-> <c- nf>example_with_stp</c-><c- p>()</c-> <c- p>{</c->
  <c- n>asio</c-><c- o>::</c-><c- n>static_thread_pool</c-> <c- n>stp</c-><c- p>(</c-><c- mi>8</c-><c- p>);</c->

  <c- c1>// require is ok, since static_thread_pool supports blocking.always</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>stp</c-><c- p>.</c-><c- n>executor</c-><c- p>(),</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- c1>// query is ok and informative, since static_thread_pool supports blocking_t</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-><c- p>)</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"ex blocking.possibly"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</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>"Before wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>stp</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"After wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Since the executor provided by <code class="highlight"><c- n>static_thread_pool</c-></code> supports both <code class="highlight"><c- n>query</c-></code> and <code class="highlight"><c- n>require</c-></code> for <code class="highlight"><c- n>blocking_t</c-></code>, we get a deterministic result, where <code class="highlight"><c- n>i</c-><c- o>==</c-><c- mi>2</c-></code> both before and after the wait on the <code class="highlight"><c- n>stp</c-></code> context:</p>
   <blockquote>
<pre class="highlight"><c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>Before</c-> <c- n>wait</c-> <c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>After</c-> <c- n>wait</c-> <c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
</pre>
   </blockquote>
   <h4 class="heading settled" data-level="3.1.1" id="examples-custom-exec"><span class="secno">3.1.1. </span><span class="content">Writing a custom executor</span><a class="self-link" href="#examples-custom-exec"></a></h4>
   <p>It is relatively straightforward to add support for a standard property to a custom executor. Below we show a custom <code class="highlight"><c- n>toy_tbb_context</c-></code> that has support for querying <code class="highlight"><c- n>blocking_t</c-></code> and requiring <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-></code>. Our toy context is built on top of the Threading Building Blocks (TBB) library which is an open-source C++ library for threading. The <code class="highlight"><c- n>toy_tbb_context</c-></code> maintains a TBB <code class="highlight"><c- n>task_group</c-></code>, which represents a group of tasks that the TBB library will schedule on to its internal thread pool. The <code class="highlight"><c- n>toy_tbb_context</c-><c- o>::</c-><c- n>executor_</c-></code> has a member variable <code class="highlight"><c- n>blocking_value_</c-></code> that holds the state of the property, which has a value of <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-></code> by default. The function <code class="highlight"><c- n>query</c-></code> returns the value and the function <code class="highlight"><c- n>require</c-></code> returns a new <code class="highlight"><c- n>executor_</c-></code> that has a reference to the same <code class="highlight"><c- n>toy_tbb_context</c-></code> but with <code class="highlight"><c- n>blocking_value_</c-></code> set to <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code>. The <code class="highlight"><c- n>executor_</c-></code>'s member function <code class="highlight"><c- n>execute</c-></code> calls <code class="highlight"><c- n>task_group</c-><c- o>::</c-><c- n>run</c-></code> to implement a non-blocking <code class="highlight"><c- n>execute</c-></code> and a calls <code class="highlight"><c- n>task_group</c-><c- o>::</c-><c- n>run_and_wait</c-></code> to implement a blocking <code class="highlight"><c- n>execute</c-></code>. The <code class="highlight"><c- n>toy_tbb_context</c-></code> provides a member function <code class="highlight"><c- n>wait</c-></code> that blocks until all tasks in its <code class="highlight"><c- n>task_group</c-></code> are complete.</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>toy</c-> <c- p>{</c->
  <c- k>class</c-> <c- nc>toy_tbb_context</c-> <c- p>{</c->
  <c- k>public</c-><c- o>:</c->
    <c- k>class</c-> <c- nc>executor_</c-> <c- p>{</c->
    <c- k>public</c-><c- o>:</c->
      <c- k>constexpr</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-> <c- n>query</c-><c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>blocking_value_</c-><c- p>;</c->
      <c- p>}</c->
      <c- k>auto</c-> <c- n>require</c-><c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-> <c- n>val</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>executor_</c-><c- p>{</c-><c- n>context_</c-><c- p>,</c-> <c- n>val</c-><c- p>};</c->
      <c- p>}</c->
      <c- b>bool</c-> <c- k>operator</c-><c- o>==</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- k>this</c-> <c- o>==</c-> <c- o>&amp;</c-><c- n>other</c-><c- p>;</c-> <c- p>}</c->
      <c- b>bool</c-> <c- k>operator</c-><c- o>!=</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- k>this</c-> <c- o>!=</c-> <c- o>&amp;</c-><c- n>other</c-><c- p>;</c-> <c- p>}</c->
      <c- n>executor_</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>e</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
      <c- o>~</c-><c- n>executor_</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

      <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Invocable</c-><c- o>></c->
      <c- b>void</c-> <c- n>execute</c-><c- p>(</c-><c- n>Invocable</c-> <c- o>&amp;&amp;</c-><c- n>f</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c->
        <c- k>if</c-> <c- p>(</c-><c- n>blocking_value_</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always</c-><c- p>)</c-> <c- p>{</c->
          <c- n>context_</c-><c- p>.</c-><c- n>task_group_</c-><c- p>.</c-><c- n>run_and_wait</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Invocable</c-><c- o>></c-><c- p>(</c-><c- n>f</c-><c- p>));</c->
        <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
          <c- n>context_</c-><c- p>.</c-><c- n>task_group_</c-><c- p>.</c-><c- n>run</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Invocable</c-><c- o>></c-><c- p>(</c-><c- n>f</c-><c- p>));</c->
        <c- p>}</c->
      <c- p>}</c->

    <c- k>private</c-><c- o>:</c->
      <c- k>friend</c-> <c- n>toy_tbb_context</c-><c- p>;</c->
      <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-> <c- n>blocking_value_</c-><c- p>;</c-> 
      <c- n>toy_tbb_context</c-> <c- o>&amp;</c-><c- n>context_</c-><c- p>;</c->
      <c- n>executor_</c-><c- p>(</c-><c- n>toy_tbb_context</c-><c- o>&amp;</c-> <c- n>context</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>:</c-> <c- n>context_</c-><c- p>(</c-><c- n>context</c-><c- p>)</c-> <c- p>{}</c->
      <c- n>executor_</c-><c- p>(</c-><c- n>toy_tbb_context</c-><c- o>&amp;</c-> <c- n>context</c-><c- p>,</c->
                <c- k>const</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>&amp;</c-> <c- n>blocking_val</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>:</c->
        <c- n>context_</c-><c- p>(</c-><c- n>context</c-><c- p>),</c-> <c- n>blocking_value_</c-><c- p>(</c-><c- n>blocking_val</c-><c- p>)</c-> <c- p>{}</c->
    <c- p>};</c->
    <c- n>executor_</c-> <c- nf>executor</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>executor_</c-><c- p>{</c-><c- o>*</c-><c- k>this</c-><c- p>};</c-> <c- p>}</c->

    <c- b>void</c-> <c- nf>wait</c-><c- p>()</c-> <c- p>{</c-> <c- n>task_group_</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c-> <c- p>}</c->

  <c- k>private</c-><c- o>:</c->
    <c- n>tbb</c-><c- o>::</c-><c- n>task_group</c-> <c- n>task_group_</c-><c- p>;</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p>We can replace the <code class="highlight"><c- n>static_thread_pool</c-></code> in our previous example with our <code class="highlight"><c- n>toy_tbb_context</c-></code> and, due to its support of <code class="highlight"><c- n>blocking_t</c-></code>, also get deterministic results, where <code class="highlight"><c- n>i</c-> <c- o>==</c-> <c- mi>2</c-></code> both before and after the wait.</p>
<pre class="highlight"><c- b>void</c-> <c- nf>example_with_toy_tbb</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context</c-> <c- n>ttc</c-><c- p>;</c->

  <c- c1>// require is ok, since toy_tbb_context supports blocking.always</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>(),</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->

  <c- c1>// query is ok and informative, since toy_tbb_context supports blocking_t</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-><c- p>)</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"ex blocking.possibly"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</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>"Before wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"After wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>It should be noted that executors, senders and schedulers are <strong>not</strong> required to support all of the standard properties. We implemented a <code class="highlight"><c- n>toy_tbb_context_no_support</c-></code> as follows without any support for properties. In this implementation, the <code class="highlight"><c- n>execute</c-></code> function always calls the non-blocking <code class="highlight"><c- n>task_group</c-><c- o>::</c-><c- n>run</c-></code>.</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>toy</c-> <c- p>{</c->
  <c- k>class</c-> <c- nc>toy_tbb_context_no_support</c-> <c- p>{</c->
  <c- k>public</c-><c- o>:</c->
    <c- k>class</c-> <c- nc>executor_</c-> <c- p>{</c->
    <c- k>public</c-><c- o>:</c->
      <c- b>bool</c-> <c- k>operator</c-><c- o>==</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- k>this</c-> <c- o>==</c-> <c- o>&amp;</c-><c- n>other</c-><c- p>;</c-> <c- p>}</c->
      <c- b>bool</c-> <c- k>operator</c-><c- o>!=</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- k>this</c-> <c- o>!=</c-> <c- o>&amp;</c-><c- n>other</c-><c- p>;</c-> <c- p>}</c->
      <c- n>executor_</c-><c- p>(</c-><c- k>const</c-> <c- n>executor_</c-><c- o>&amp;</c-> <c- n>e</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
      <c- o>~</c-><c- n>executor_</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

      <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Invocable</c-><c- o>></c->
      <c- b>void</c-> <c- n>execute</c-><c- p>(</c-><c- n>Invocable</c-> <c- o>&amp;&amp;</c-><c- n>f</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c->
        <c- n>context_</c-><c- p>.</c-><c- n>task_group_</c-><c- p>.</c-><c- n>run</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Invocable</c-><c- o>></c-><c- p>(</c-><c- n>f</c-><c- p>));</c->
      <c- p>}</c->

    <c- k>private</c-><c- o>:</c->
      <c- n>toy_tbb_context_no_support</c-> <c- o>&amp;</c-><c- n>context_</c-><c- p>;</c->
      <c- k>friend</c-> <c- n>toy_tbb_context_no_support</c-><c- p>;</c->
      <c- n>executor_</c-><c- p>(</c-><c- n>toy_tbb_context_no_support</c-><c- o>&amp;</c-> <c- n>context</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>:</c-> <c- n>context_</c-><c- p>(</c-><c- n>context</c-><c- p>)</c-> <c- p>{}</c->
    <c- p>};</c->

    <c- n>executor_</c-> <c- nf>executor</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>executor_</c-><c- p>{</c-><c- o>*</c-><c- k>this</c-><c- p>};</c-> <c- p>}</c->

    <c- b>void</c-> <c- nf>wait</c-><c- p>()</c-> <c- p>{</c->
      <c- n>task_group_</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
    <c- p>}</c->

  <c- k>private</c-><c- o>:</c->
    <c- n>tbb</c-><c- o>::</c-><c- n>task_group</c-> <c- n>task_group_</c-><c- p>;</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p>We can no longer plug this context in directly for <code class="highlight"><c- n>static_thread_pool</c-></code> in our example, because the use of <code class="highlight"><c- n>require</c-></code> will not compile. However if we are unsure that an executor will provide <code class="highlight"><c- n>require</c-></code> for a requirable property, we can use <code class="highlight"><c- n>prefer</c-></code> instead, which will call <code class="highlight"><c- n>require</c-></code> only if it is supported; otherwise, it returns an executor that has the same properties established as the executor that was passed to it. It is also intended that all standard properties have reasonable defaults, so <code class="highlight"><c- n>query</c-></code> will return an accurate but broad result even if the executor does not explicitly support <code class="highlight"><c- n>query</c-></code>. In the case of <code class="highlight"><c- n>blocking_t</c-></code>, the default <code class="highlight"><c- n>query</c-></code> returns <code class="highlight"><c- n>blocking</c-><c- o>::</c-><c- n>possibly</c-></code>, which is never incorrect.  Therefore to use the <code class="highlight"><c- n>toy_tbb_context_no_support</c-></code>, we update our example as shown:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>example_with_toy_tbb_no_support</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context_no_support</c-> <c- n>ttc</c-><c- p>;</c->

  <c- c1>// prefer is ok, even for an executor that does not explicitly support blocking_t</c->
  <c- c1>// it returns an executor with the same properties</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>(),</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Preferred blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- c1>// query is ok, even for an executor that does not explicitly support blocking_t</c->
  <c- c1>// the result is broad but still useful</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-><c- p>)</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"ex blocking.possibly"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- b>int</c-> <c- n>j</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- n>i</c-><c- p>.</c-><c- n>compare_exchange_strong</c-><c- p>(</c-><c- n>j</c-><c- p>,</c-> <c- mi>2</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>"Before wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"After wait i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Since, without blocking, our example now contains a real race, we use an <code class="highlight"><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-></code> and <code class="highlight"><c- n>compare_exchange_strong</c-></code>. Depending on which operation on <code class="highlight"><c- n>i</c-></code> occurs first, 
the result after the wait may be 1 or 2. An example output, where the second call to <code class="highlight"><c- n>execute</c-></code> completes first, and therefore <code class="highlight"><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-></code>, is shown below:</p>
   <blockquote>
<pre class="highlight"><c- n>Preferred</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>ex</c-> <c- n>blocking</c-><c- p>.</c-><c- n>possibly</c->
<c- n>Before</c-> <c- n>wait</c-> <c- n>i</c-> <c- o>==</c-> <c- mi>0</c->
<c- n>After</c-> <c- n>wait</c-> <c- n>i</c-> <c- o>==</c-> <c- mi>1</c->
</pre>
   </blockquote>
   <h4 class="heading settled" data-level="3.1.2" id="examples-any-executor"><span class="secno">3.1.2. </span><span class="content">Using <code class="highlight"><c- n>any_executor</c-></code></span><a class="self-link" href="#examples-any-executor"></a></h4>
   <p>We can wrap the executor types returned by <code class="highlight"><c- n>static_thread_pool</c-></code>, <code class="highlight"><c- n>toy_tbb_context</c-></code> and <code class="highlight"><c- n>toy_tbb_context_no_support</c-></code> in the polymorphic wrapper <code class="highlight"><c- n>any_executor</c-></code>. For demonstration, we introduce a trivial <code class="highlight"><c- n>algorithm</c-></code> that contains the two calls to <code class="highlight"><c- n>execute</c-></code> as show below. Because the executor types of both <code class="highlight"><c- n>static_thread_pool</c-></code> and <code class="highlight"><c- n>toy_tbb_context</c-></code> support <code class="highlight"><c- n>require</c-></code> for <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-></code>, they can be both be wrapped in <code class="highlight"><c- n>any_exec_type</c-></code>.</p>
<pre class="highlight"><c- k>using</c-> <c- n>any_exec_type</c-> <c- o>=</c-> 
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>any_executor</c-><c- o>&lt;</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- o>></c-><c- p>;</c->

<c- b>void</c-> <c- nf>algorithm</c-><c- p>(</c-><c- n>any_exec_type</c-> <c- n>ex0</c-><c- p>)</c-> <c- p>{</c->
  <c- c1>// since blocking_t::always_t is supported, we know we can require it</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ex0</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- c1>// Since it’s blocking, we don’t need the compare_exchange</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</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 == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>example_with_stp</c-><c- p>()</c-> <c- p>{</c->
  <c- n>asio</c-><c- o>::</c-><c- n>static_thread_pool</c-> <c- n>stp</c-><c- p>(</c-><c- mi>8</c-><c- p>);</c->
  <c- n>algorithm</c-><c- p>(</c-><c- n>stp</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>stp</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>example_with_toy_tbb</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context</c-> <c- n>ttc</c-><c- p>;</c->
  <c- n>algorithm</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
<c- p>}</c->
</pre>
   <p>Our <code class="highlight"><c- n>toy_tbb_context_no_support</c-></code> does not, however, support <code class="highlight"><c- n>require</c-></code> for <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-></code> and so it cannot be wrapped with <code class="highlight"><c- n>any_exec_type</c-></code>.  If we are unsure if an executor supports <code class="highlight"><c- n>require</c-></code> for a property, we can again rely on <code class="highlight"><c- n>prefer</c-></code> and create a different <code class="highlight"><c- n>any_executor</c-></code> type that uses the <code class="highlight"><c- n>prefer_only</c-></code> property adapter.</p>
<pre class="highlight"><c- k>using</c-> <c- n>any_exec_ptype</c-> <c- o>=</c-> 
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>any_executor</c-><c- o>&lt;</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>prefer_only</c-><c- o>&lt;</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- o>>></c-><c- p>;</c->

<c- b>void</c-> <c- nf>algorithm_with_prefer</c-><c- p>(</c-><c- n>any_exec_ptype</c-> <c- n>ex0</c-><c- p>)</c-> <c- p>{</c->
  <c- c1>// blocking_t::always_t might be supported, but we don’t know, so prefer</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>ex0</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Preferred blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>)</c-> <c- p>{</c->
    <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
    <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</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 == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
    <c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
    <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- b>int</c-> <c- n>j</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- n>i</c-><c- p>.</c-><c- n>compare_exchange_strong</c-><c- p>(</c-><c- n>j</c-><c- p>,</c-> <c- mi>2</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 == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- p>}</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>example_with_toy_tbb_no_support</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context_no_support</c-> <c- n>ttc</c-><c- p>;</c->
  <c- n>algorithm_with_prefer</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
<c- p>}</c->
</pre>
   <p>Since <code class="highlight"><c- n>query</c-></code> and <code class="highlight"><c- n>prefer</c-></code> are supported by the executor types of <code class="highlight"><c- n>static_thread_pool</c-></code>, <code class="highlight"><c- n>toy_tbb_context</c-></code> and <code class="highlight"><c- n>toy_tbb_context_no_support</c-></code>, 
any of these executors could be passed to our <code class="highlight"><c- n>algorithm_with_prefer</c-></code>.</p>
   <h3 class="heading settled" data-level="3.2" id="examples-custom"><span class="secno">3.2. </span><span class="content">Using custom properties</span><a class="self-link" href="#examples-custom"></a></h3>
   <p>It is also fairly straightforward to create a custom property. To demonstrate this, we implemented a <code class="highlight"><c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-></code> property to control tracing in our <code class="highlight"><c- n>toy_tbb_context</c-></code>. This property holds a value of <code class="highlight">true</code> if tracing is on and <code class="highlight">false</code> if tracing is off. We provide a free function <code class="highlight"><c- n>query</c-></code> that returns a default value of false, i.e. tracing is off.</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>toy</c-> <c- p>{</c->
  <c- k>struct</c-> <c- n>tracing_t</c->
  <c- p>{</c->
    <c- n>tracing_t</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
    <c- k>constexpr</c-> <c- nf>tracing_t</c-><c- p>(</c-><c- b>bool</c-> <c- n>val</c-><c- p>)</c-> <c- o>:</c-> <c- n>value_</c-><c- p>(</c-><c- n>val</c-><c- p>)</c-> <c- p>{}</c->

    <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_applicable_property_v</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>executor</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>;</c->
    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_requirable</c-> <c- o>=</c-> true<c- p>;</c->
    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_preferable</c-> <c- o>=</c-> true<c- p>;</c->
    <c- k>using</c-> <c- n>polymorphic_query_result_type</c-> <c- o>=</c-> <c- b>bool</c-><c- p>;</c->

    <c- k>constexpr</c-> <c- k>explicit</c-> <c- k>operator</c-> <c- nf>bool</c-><c- p>()</c-> <c- k>const</c->
    <c- p>{</c->
      <c- k>return</c-> <c- n>value_</c-><c- p>;</c->
    <c- p>}</c->
  <c- k>private</c-><c- o>:</c->
    <c- b>bool</c-> <c- n>value_</c-><c- p>{</c->false<c- p>};</c->
  <c- p>};</c->
    
  <c- kr>inline</c-> <c- k>constexpr</c-> <c- n>tracing_t</c-> <c- n>tracing</c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>E</c-><c- o>></c->
  <c- k>constexpr</c-> <c- b>bool</c-> <c- n>query</c-><c- p>(</c-><c- k>const</c-> <c- n>E</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>tracing_t</c-><c- o>&amp;</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> false<c- p>;</c-> <c- p>}</c->
<c- p>}</c->
</pre>
   <h4 class="heading settled" data-level="3.2.1" id="examples-custom-custom"><span class="secno">3.2.1. </span><span class="content">Modifying our custom executor</span><a class="self-link" href="#examples-custom-custom"></a></h4>
   <p>The support in our custom <code class="highlight"><c- n>toy_tbb_executor</c-></code> is similar to the support for <code class="highlight"><c- n>blocking_t</c-></code>.  We show only the additions and changes below:</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>toy</c-> <c- p>{</c->
  <c- k>class</c-> <c- nc>toy_tbb_context</c-> <c- p>{</c->
  <c- k>public</c-><c- o>:</c->
    <c- k>class</c-> <c- nc>executor_</c-> <c- p>{</c->
    <c- k>public</c-><c- o>:</c->
      <c- c1>// ...</c->
      <c- k>constexpr</c-> <c- b>bool</c-> <c- n>query</c-><c- p>(</c-><c- k>const</c-> <c- n>tracing_t</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c->
        <c- k>return</c-> <c- k>static_cast</c-><c- o>&lt;</c-><c- b>bool</c-><c- o>></c-><c- p>(</c-><c- n>tracing_value_</c-><c- p>);</c->
      <c- k>auto</c-> <c- nf>require</c-><c- p>(</c-><c- k>const</c-> <c- n>tracing_t</c-><c- o>&amp;</c-> <c- n>val</c-><c- p>)</c-> <c- k>const</c-> <c- k>noexcept</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>executor_</c-><c- p>{</c-><c- n>context_</c-><c- p>,</c-> <c- n>blocking_value_</c-><c- p>,</c-> <c- n>val</c-><c- p>};</c->
      <c- p>}</c->
      <c- c1>// ...</c->
      <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Invocable</c-><c- o>></c->
      <c- b>void</c-> <c- n>execute</c-><c- p>(</c-><c- n>Invocable</c-> <c- o>&amp;&amp;</c-><c- n>f</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c->
        <c- k>if</c-> <c- p>(</c-><c- n>tracing_value_</c-><c- p>)</c->
          <c- o>++</c-><c- n>context_</c-><c- p>.</c-><c- n>executions_</c-><c- p>;</c->

        <c- k>if</c-> <c- p>(</c-><c- n>blocking_value_</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always</c-><c- p>)</c-> <c- p>{</c->
          <c- n>context_</c-><c- p>.</c-><c- n>task_group_</c-><c- p>.</c-><c- n>run_and_wait</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Invocable</c-><c- o>></c-><c- p>(</c-><c- n>f</c-><c- p>));</c->
        <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
          <c- n>context_</c-><c- p>.</c-><c- n>task_group_</c-><c- p>.</c-><c- n>run</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>Invocable</c-><c- o>></c-><c- p>(</c-><c- n>f</c-><c- p>));</c->
        <c- p>}</c->
      <c- p>}</c->
    <c- k>private</c-><c- o>:</c->
      <c- c1>// ...</c->
      <c- n>tracing_t</c-> <c- n>tracing_value_</c-><c- p>;</c->
      <c- c1>// ...</c->
      <c- n>executor_</c-><c- p>(</c-><c- n>toy_tbb_context</c-><c- o>&amp;</c-> <c- n>context</c-><c- p>,</c-> 
                <c- k>const</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>&amp;</c-> <c- n>blocking_val</c-><c- p>,</c-> 
                <c- k>const</c-> <c- n>tracing_t</c-><c- o>&amp;</c-> <c- n>tracing_val</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>:</c->
          <c- n>context_</c-><c- p>(</c-><c- n>context</c-><c- p>),</c->
          <c- n>blocking_value_</c-><c- p>(</c-><c- n>blocking_val</c-><c- p>),</c->
          <c- n>tracing_value_</c-><c- p>(</c-><c- n>tracing_val</c-><c- p>)</c-> <c- p>{}</c->
    <c- p>};</c->
    <c- c1>// ...</c->
    <c- b>int</c-> <c- nf>traced_executions</c-><c- p>()</c-> <c- k>noexcept</c-> <c- p>{</c-> <c- k>return</c-> <c- n>executions_</c-><c- p>;</c-> <c- p>}</c->
  <c- k>private</c-><c- o>:</c->
    <c- c1>// ...</c->
    <c- n>std</c-><c- o>::</c-><c- n>atomic</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>executions_</c-><c- p>;</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p>We can now <code class="highlight"><c- n>require</c-></code> this property to turn tracing on and off for the <code class="highlight"><c- n>toy_tbb_context</c-><c- o>::</c-><c- n>executor_</c-></code> as shown below:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>example_with_toy_tbb</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context</c-> <c- n>ttc</c-><c- p>;</c->

  <c- c1>// require is ok, since toy_tbb_context supports blocking.always</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>(),</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- c1>// query is ok and informative, since toy_tbb_context supports blocking_t</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-><c- p>)</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"ex blocking.possibly"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</c-><c- p>;</c-> <c- p>});</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- k>auto</c-> <c- n>tex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- p>{</c->true<c- p>});</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required toy::tracing_t{true}"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</c-><c- p>;</c-> <c- p>});</c->
  <c- n>ttc</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>The output of the above code is as follows:</p>
   <blockquote>
<pre class="highlight"><c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>0</c->
<c- n>Required</c-> <c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- p>{</c->true<c- p>}</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>2</c->
</pre>
   </blockquote>
   <p><code class="highlight"><c- n>static_thread_pool</c-></code> does not support this property and since it is a standard executor type, we cannot add support. However, we have provided a reasonable default for <code class="highlight"><c- n>query</c-></code>, tracing is off. So, we can both <code class="highlight"><c- n>query</c-></code> and <code class="highlight"><c- n>prefer</c-></code> this property on the executor type from <code class="highlight"><c- n>static_thread_pool</c-></code>, with <code class="highlight"><c- n>prefer</c-></code> returning an executor with the same properties as the executor that was passed to it.</p>
<pre class="highlight"><c- b>void</c-> <c- nf>example_with_stp</c-><c- p>()</c-> <c- p>{</c->
  <c- n>asio</c-><c- o>::</c-><c- n>static_thread_pool</c-> <c- n>stp</c-><c- p>(</c-><c- mi>8</c-><c- p>);</c->

  <c- c1>// require is ok, since static_thread_pool supports blocking.always</c->
  <c- k>auto</c-> <c- n>ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>stp</c-><c- p>.</c-><c- n>executor</c-><c- p>(),</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- c1>// query is ok and informative, since static_thread_pool supports blocking_t</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>possibly</c-><c- p>)</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"ex blocking.possibly"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- c1>// prefer is ok, even for an executor that does not explicitly support toy::tracing_t</c->
  <c- c1>// it returns an executor with the same properties</c->
  <c- k>auto</c-> <c- n>tex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- p>{</c->true<c- p>});</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Preferred toy::tracing_t{true}"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</c-><c- p>;</c-> <c- p>});</c->
  <c- n>stp</c-><c- p>.</c-><c- n>wait</c-><c- p>();</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"i == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <h4 class="heading settled" data-level="3.2.2" id="examples-custom-any-executor"><span class="secno">3.2.2. </span><span class="content">Using <code class="highlight"><c- n>any_executor</c-></code> again</span><a class="self-link" href="#examples-custom-any-executor"></a></h4>
   <p>Lastly, we can wrap both <code class="highlight"><c- n>static_thread_pool</c-></code> and <code class="highlight"><c- n>toy_tbb_context</c-></code> in <code class="highlight"><c- n>any_executor</c-></code> and use both the standard <code class="highlight"><c- n>blocking_t</c-></code> and the custom <code class="highlight"><c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-></code> properties. Since <code class="highlight"><c- n>static_thread_pool</c-></code> does not explicitly support <code class="highlight"><c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-></code>, we must again use the <code class="highlight"><c- n>prefer_only</c-></code> adapter if we want our algorithms to support both executors. In our example, we also demonstrate that implicit conversions support construction of an <code class="highlight"><c- n>any_executor</c-></code> from another <code class="highlight"><c- n>any_executor</c-></code> that has the same supported properties even if they are in a different order in the template argument list.</p>
<pre class="highlight"><c- k>using</c-> <c- n>any_exec_type</c-> <c- o>=</c-> 
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>any_executor</c-><c- o>&lt;</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>prefer_only</c-><c- o>&lt;</c-><c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- o>></c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- o>></c-><c- p>;</c->

<c- k>using</c-> <c- n>any_almost_same_exec_type</c-> <c- o>=</c-> 
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>any_executor</c-><c- o>&lt;</c-><c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- p>,</c->
                                <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>prefer_only</c-><c- o>&lt;</c-><c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- o>>></c-><c- p>;</c->

<c- b>void</c-> <c- nf>algorithm</c-><c- p>(</c-><c- n>any_exec_type</c-> <c- n>ex</c-><c- p>)</c-> <c- p>{</c->
  <c- k>auto</c-> <c- n>tt_ex</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Required blocking.always"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- k>if</c-> <c- p>(</c-><c- n>asio</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>tt_ex</c-><c- p>,</c-> <c- n>toy</c-><c- o>::</c-><c- n>tracing</c-><c- p>))</c->
    <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"Using tracing"</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tt_ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>1</c-><c- p>;</c-> <c- p>});</c->
  <c- n>asio</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-><c- p>(</c-><c- n>tt_ex</c-><c- p>,</c-> <c- p>[</c-><c- o>&amp;</c-><c- n>i</c-><c- p>]()</c-> <c- p>{</c-> <c- k>if</c-> <c- p>(</c-><c- n>i</c-> <c- o>==</c-> <c- mi>1</c-><c- p>)</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>2</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 == "</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>algorithm_tracing</c-><c- p>(</c-><c- n>any_almost_same_exec_type</c-> <c- n>ex</c-><c- p>)</c->
<c- p>{</c->
  <c- k>auto</c-> <c- n>tracing_exec</c-> <c- o>=</c-> <c- n>asio</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>toy</c-><c- o>::</c-><c- n>tracing_t</c-><c- p>{</c->true<c- p>});</c->
  <c- n>algorithm</c-><c- p>(</c-><c- n>tracing_exec</c-><c- p>);</c->
<c- p>}</c->

<c- b>void</c-> <c- nf>combined_example</c-><c- p>()</c-> <c- p>{</c->
  <c- n>toy</c-><c- o>::</c-><c- n>toy_tbb_context</c-> <c- n>ttc</c-><c- p>;</c->
  <c- n>algorithm</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>algorithm_tracing</c-><c- p>(</c-><c- n>ttc</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->

  <c- n>asio</c-><c- o>::</c-><c- n>static_thread_pool</c-> <c- n>stp</c-><c- p>(</c-><c- mi>4</c-><c- p>);</c->
  <c- n>algorithm</c-><c- p>(</c-><c- n>stp</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
  <c- n>algorithm_tracing</c-><c- p>(</c-><c- n>stp</c-><c- p>.</c-><c- n>executor</c-><c- p>());</c->
  <c- n>std</c-><c- o>::</c-><c- n>cout</c-> <c- o>&lt;&lt;</c-> <c- s>"traced_executions == "</c-> <c- o>&lt;&lt;</c-> <c- n>ttc</c-><c- p>.</c-><c- n>traced_executions</c-><c- p>()</c-> <c- o>&lt;&lt;</c-> <c- n>std</c-><c- o>::</c-><c- n>endl</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>When run, this example turns on tracing for the <code class="highlight"><c- n>toy_tbb_context</c-></code> executor when <code class="highlight"><c- n>algorithm_tracing</c-></code> is called:</p>
   <blockquote>
<pre class="highlight"><c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>0</c->
<c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>Using</c-> <c- n>tracing</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>Required</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c->
<c- n>i</c-> <c- o>==</c-> <c- mi>2</c->
<c- n>traced_executions</c-> <c- o>==</c-> <c- mi>2</c->
</pre>
   </blockquote>
   <h2 class="heading settled" data-level="4" id="wording-bugs"><span class="secno">4. </span><span class="content">Small Issues</span><a class="self-link" href="#wording-bugs"></a></h2>
   <p>For small issues that have an obvious resolution, mostly wording bugs, we created issues in the <a href="https://github.com/executors/executors/issues">Executors GitHub</a> repository.  The GitHub issues are listed here, but they can be resolved easily by the authors of P0443 and don’t need to be discussed in LEWG.</p>
   <ul>
    <li data-md>
     <p>any_executor section is in the wrong place <a href="https://github.com/executors/executors/issues/488">#488</a></p>
    <li data-md>
     <p>Use of undefined name "Property" in behavioral properties <a href="https://github.com/executors/executors/issues/489">#489</a></p>
    <li data-md>
     <p>Wrong property type in static_thread_pool sender and executor summaries <a href="https://github.com/executors/executors/issues/490">#490</a></p>
    <li data-md>
     <p>Incorrect syntax in description of allocator_t&lt;ProtoAllocator> property <a href="https://github.com/executors/executors/issues/491">#491</a></p>
    <li data-md>
     <p>bad_executor refers to non-existent any_executor::bulk_execute <a href="https://github.com/executors/executors/issues/493">#493</a></p>
    <li data-md>
     <p>S::Ei should be S::Ni <a href="https://github.com/executors/executors/issues/494">#494</a></p>
    <li data-md>
     <p>prefer_only example is out of date <a href="https://github.com/executors/executors/issues/498">#498</a></p>
   </ul>
   <h2 class="heading settled" data-level="5" id="issues"><span class="secno">5. </span><span class="content">Issues</span><a class="self-link" href="#issues"></a></h2>
   <p>Here is a list of issue that we think deserve more discussion in LEWG.  Some of the issues have a suggested resolution which we would like LEWG to approve and the P0443 authors to implement.  Some issues merely identify a problem that we would like the authors of P0443 to solve, possibly with guidance from LEWG.  Any changes made in response to <a href="#blocking">§ 5.2 Generic blocking adapter is not implementable</a> or <a href="#bulk_guarantee">§ 5.7 bulk_guarantee specification should match execution policies</a> should also be reviewed by SG1.</p>
   <h3 class="heading settled" data-level="5.1" id="applicability"><span class="secno">5.1. </span><span class="content">Should properties be usable with non-executors?</span><a class="self-link" href="#applicability"></a></h3>
   <p>All of the properties defined in P0443 have</p>
   <blockquote>
<pre class="highlight"><code class="highlight"><c- k><c- k>template</c-></c-> <c- o><c- o>&lt;</c-></c-><c- k><c- k>class</c-></c-> <c- nc><c- nc>T</c-></c-><c- o><c- o>></c-></c->
  <c- k><c- k>static</c-></c-> <c- k><c- k>constexpr</c-></c-> <c- b><c- b>bool</c-></c-> <c- n><c- n>is_applicable_property_v</c-></c-> <c- o><c- o>=</c-></c-> <c- n><c- n>executor</c-></c-><c- o><c- o>&lt;</c-></c-><c- n><c- n>T</c-></c-><c- o><c- o>></c-></c-><c- p><c- p>;</c-></c->
</code></pre>
   </blockquote>
    This limits the property to types that satisfy the <code class="highlight"><c- n>executor</c-></code> concept.  Any attempt to apply the property to something that is not an <code class="highlight"><c- n>executor</c-></code> is normally ill-formed, even if that something has the necessary <code class="highlight"><c- n>query</c-></code>, <code class="highlight"><c- n>require</c-></code>, or <code class="highlight"><c- n>prefer</c-></code> specializations that would otherwise make everything work.  For example, the first bullet in the specification of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> in P1393 is: 
   <blockquote>
    <ul>
     <li data-md>
      <p>If <code class="highlight"><c- n>is_applicable_property_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Prop0</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>Prop0</c-><c- o>::</c-><c- n>is_preferable</c-></code> is not a well-formed constant expression with value <code class="highlight">true</code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>,</c-> <c- n>Pn</c-><c- p>...)</c-></code> is ill-formed.</p>
    </ul>
   </blockquote>
    If the <code class="highlight"><c- n>is_applicable_property_v</c-></code> check fails, the call to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> is ill-formed, rather than proceeding to the fallback of returning <code class="highlight"><c- n>E</c-></code> unchanged that is normally used when a property can’t be applied to a particular executor. 
   <p>The specification for the <code class="highlight"><c- n>static_thread_pool</c-></code> sender types lists member functions that support the properties <code class="highlight"><c- n>context</c-></code>, <code class="highlight"><c- n>blocking</c-></code>, <code class="highlight"><c- n>relationship</c-></code>, <code class="highlight"><c- n>outstanding_work</c-></code>, <code class="highlight"><c- n>allocator</c-></code>, <code class="highlight"><c- n>bulk_guarantee</c-></code>, and <code class="highlight"><c- n>mapping</c-></code>.  The specification for the <code class="highlight"><c- n>static_thread_pool</c-></code> scheduler types lists member functions that support the properties <code class="highlight"><c- n>context</c-></code> and <code class="highlight"><c- n>allocator</c-></code>.</p>
   <p>Some senders satisfy the <code class="highlight"><c- n>executor</c-></code> concept (because <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>execute</c-></code> has a fallback that accepts a sender as the first argument).  It seems that <code class="highlight"><c- n>static_thread_pool</c-></code>'s senders satisfy <code class="highlight"><c- n>executor</c-></code> (because they are noexcept-copyable and equality-comparable), so the property should work with <code class="highlight"><c- n>static_thread_pool</c-></code>'s senders.  But there is no guarantee that other senders satisfy <code class="highlight"><c- n>executor</c-></code>. <code class="highlight"><c- n>static_thread_pool</c-></code>'s scheduler types are not guaranteed to satisfy <code class="highlight"><c- n>executor</c-></code>, so the properties likely cannot be applied to them.</p>
   <p>It seems that it would be useful to be able to apply these properties to senders.  Senders have access to an executor under the covers.  When users get the sender from <code class="highlight"><c- n>schedule</c-></code> and then pass it to <code class="highlight"><c- n>submit</c-></code> or <code class="highlight"><c- n>connect</c-></code> or to an asynchronous algorithm, they never have direct access to the executor.  Users who want to customize or tune the executor in some way have to go through the sender to get to the executor, but there is no standard way to do that.</p>
   <p>Similar reasoning applies to schedulers.  Schedulers dole out senders which are associated with executors.  It would be helpful for users to tell the scheduler what properties they want for their executors, and the scheduler would only create senders that are associated with executors with those properties.</p>
   <p>One possible solution to this discrepancy is to change the <code class="highlight"><c- n>is_applicable_property_v</c-></code> member of each executor property from <code class="highlight"><c- n>executor</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> to <code class="highlight"><c- n>executor</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>||</c-> <c- n>sender</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>||</c-> <c- n>scheduler</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>.  That would allow all senders and schedulers to support these properties if desired.  Support would still be opt-in; senders and schedulers would have to define the necessary overloads of <code class="highlight"><c- n>query</c-></code>, <code class="highlight"><c- n>require</c-></code>, and/or <code class="highlight"><c- n>prefer</c-></code> to actually support the properties.</p>
   <p>The other way for senders and schedulers to support these properties is to specialize <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_applicable_property</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> as described in "Property applicability trait" in <a data-link-type="biblio" href="#biblio-p1393">[P1393]</a>: "It may be specialized to indicate applicability of a property to a type."  Doing it this way can be verbose, requiring a specialization for each supported property by each non-executor class template.</p>
   <p>The inconsistency in the use of properties by <code class="highlight"><c- n>static_thread_pool</c-></code>'s schedulers needs to be dealt with in some way.  The three obvious choices are:</p>
   <ol>
    <li data-md>
     <p>Remove the support for properties, deleting the <code class="highlight"><c- n>query</c-></code> and <code class="highlight"><c- n>require</c-></code> functions from the scheduler types specification in section 2.5.3.  This is not an ideal solution because it removed functionality that we feel is useful.</p>
    <li data-md>
     <p>Change the <code class="highlight"><c- n>is_applicable_property_v</c-></code> members of all the relevant properties to have the value <code class="highlight"><c- n>executor</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>||</c-> <c- n>sender</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>||</c-> <c- n>scheduler</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>.  There are concerns that this disjunction, while not part of a concept definition, could still increase compile-time unnecessarily.</p>
    <li data-md>
     <p>Change the <code class="highlight"><c- n>is_applicable_property_v</c-></code> members of all the relevant properties to have the value <code class="highlight">true</code>.  Some members of our group think that using a property defined in the <code class="highlight"><c- n>execution</c-></code> namespace is enough of an opt-in, and don’t think that properties need to restrict their applicability.</p>
    <li data-md>
     <p>Specify that <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_applicable_property</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is specialized to have a base characteristic of <code class="highlight"><c- n>true_type</c-></code> for scheduler types and the relevant properties.  This is the most cumbersome solution, but it is the mechanism endorsed by P1393.</p>
   </ol>
   <p>The review group agreed that this is an issue that needs to be addressed, but could not agree on the best way to address it.  There was some support for all options other than option #1.  In the current <a data-link-type="biblio" href="#biblio-asio">[Asio]</a> implementation of <code class="highlight"><c- n>static_thread_pool</c-></code>, a different approach was taken to solving this issue: the same template class implements the thread pool’s executors, senders, and schedulers.  So that class satisfies all three <code class="highlight"><c- n>executor</c-></code>, <code class="highlight"><c- n>sender</c-></code>, and <code class="highlight"><c- n>scheduler</c-></code> concepts.</p>
   <p>Even though properties should already work as specified for <code class="highlight"><c- n>static_thread_pool</c-></code>'s sender types, it would be good if a similar approach was taken with the sender types.  Or at least add a non-normative note pointing out that the properties work because the sender types satisfy the <code class="highlight"><c- n>executor</c-></code> concept.</p>
   <h3 class="heading settled" data-level="5.2" id="blocking"><span class="secno">5.2. </span><span class="content">Generic blocking adapter is not implementable</span><a class="self-link" href="#blocking"></a></h3>
   <p>The specification for <code class="highlight"><c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-></code> in section 2.2.12.2.1 contains:</p>
   <blockquote>
     This customization uses an adapter to implement the <code class="highlight"><c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-></code> property. 
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Executor</c-><c- o>></c->
  <c- k>friend</c-> <c- n>see</c-><c- o>-</c-><c- n>below</c-> <c- n>require</c-><c- p>(</c-><c- n>Executor</c-> <c- n>ex</c-><c- p>,</c-> <c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-><c- p>);</c->
</pre>
   </blockquote>
   <p>This allows the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property to be applied to any executor.  If the executor does not support the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property directly, then this <code class="highlight"><c- n>require</c-></code> function will create a wrapper around the executor with the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property established.</p>
   <p>The specification for <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-></code> in section 2.2.12.1.1 contains:</p>
   <blockquote>
     If the executor has the <code class="highlight"><c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-></code> property, this customization uses an adapter to implement the <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-></code> property. 
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>Executor</c-><c- o>></c->
  <c- k>friend</c-> <c- n>see</c-><c- o>-</c-><c- n>below</c-> <c- n>require</c-><c- p>(</c-><c- n>Executor</c-> <c- n>ex</c-><c- p>,</c-> <c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- p>);</c->
</pre>
   </blockquote>
   <p>This allows the <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> property to be applied to any executor that has the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property.  If the executor does not support the <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>allowed</c-></code> property directly, then this <code class="highlight"><c- n>require</c-></code> function will create a wrapper around the executor where calls to <code class="highlight"><c- n>execute</c-></code> and <code class="highlight"><c- n>bulk_execute</c-></code> will block.</p>
   <p>The way these two properties are specified, it is possible to turn any executor into a blocking executor:</p>
<pre class="highlight"><c- c1>// This should work with almost any executor</c->
<c- n>executor</c-> <c- k>auto</c-> <c- n>blocking_ex</c-> <c- o>=</c-> 
    <c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c->
        <c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-><c- p>),</c->
        <c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>blocking_ex</c-><c- p>,</c-> <c- n>blocking</c-><c- p>)</c-> <c- o>==</c-> <c- n>blocking</c-><c- p>.</c-><c- n>always</c-><c- p>);</c->
</pre>
   <p>(It is possible for executor types to prevent these properties from being applied, but it takes extra work on the part of the executor.  If executor type <code class="highlight"><c- n>Ex</c-></code> wants to block the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property, it would have to specialize <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_applicable_property</c-><c- o>&lt;</c-><c- n>Ex</c-><c- p>,</c-> <c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-><c- o>></c-></code> to be false, or it would have to define a deleted non-member function <code class="highlight"><c- b>void</c-> <c- nf>require</c-><c- p>(</c-><c- n>Ex</c-><c- p>,</c-> <c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c-></code> to be a better match during overload resolution than the <code class="highlight"><c- n>require</c-></code> function defined by <code class="highlight"><c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-></code>.  For executor types that don’t go through this extra effort to block either of these two properties, the double-require example above will compile successfully.)</p>
   <p>This is a problem because it is not possible to implement a blocking wrapper around every executor.  Without understanding the details of the wrapped executor’s execution context, the wrapper can’t choose a synchronization primitive that will be known to work between the current thread and the wrapped executor’s execution context.  For example, using a mutex or a condition variable for synchronization won’t work if the execution context is a fiber or certain GPUs.  The standard properties for executors don’t provide enough information about the execution context for the wrapper to know the proper way to block.</p>
   <p>A standard construct that makes it easy for users to write code that won’t work is poor design.  Changes need to be made to the blocking_adaptation property.  Here are some options.  Some of them can be combined together.</p>
   <ol>
    <li data-md>
     <p><b>Remove <code class="highlight"><c- n>blocking_adaptation</c-></code> property; remove the generic <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> adapter.</b> Each executor knows best how to make it a blocking executor.  It is not possible to have a general purpose blocking adapter that always works correctly.  Converting a non-blocking executor to a blocking executor should be done by the executor itself, by implementing <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>Ex</c-><c- p>,</c-> <c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- p>)</c-></code>.  (If this approach is taken, the <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> property should become preferable. <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- o>::</c-><c- n>is_preferable</c-></code> should be changed from <code class="highlight">false</code> to <code class="highlight">true</code>.)</p>
    <li data-md>
     <p><b>Remove the generic <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> adapter.</b> The <code class="highlight"><c- n>blocking_adaptation</c-></code> property would still exist, as would the generic <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> adapter.  But there would be no generic adapter for adding the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property to an arbitrary executor.  Executors where the standard <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>allowed</c-></code> adapter will work correctly would come with the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property already established.  More unusual executors that won’t work with the standard <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> adapter won’t support the <code class="highlight"><c- n>blocking_adaptation</c-><c- p>.</c-><c- n>allowed</c-></code> property at all, and they will either provide their own implementation of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>Ex</c-><c- p>,</c-> <c- n>blocking_t</c-><c- o>::</c-><c- n>always_t</c-><c- p>)</c-></code> or not provide any means to become a blocking executor.</p>
    <li data-md>
     <p><b>The <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> adapter requires a thread-based executor.</b> It is possible to write a generic blocking adapter for executors that operate on standard threads, because many of the standard synchronization primitives are known to work correctly in that situation.  To implement this requirement for thread-based executors, change the prerequisite for the blocking adapter to, "If the executor has the <code class="highlight"><c- n>blocking_adaptation_t</c-><c- o>::</c-><c- n>allowed_t</c-></code> property and has either the <code class="highlight"><c- n>mapping_t</c-><c- o>::</c-><c- n>thread_t</c-></code> or the <code class="highlight"><c- n>mapping_t</c-><c- o>::</c-><c- n>new_thread_t</c-></code> property,".</p>
    <li data-md>
     <p><b>Change the name of <code class="highlight"><c- n>blocking_adaptation</c-></code> and/or <code class="highlight"><c- n>blocking</c-></code> to include "thread".</b> Blocking adapters work best with thread-based executors.  This could be better communicated to users by include "thread" in the property names, such as <code class="highlight"><c- n>thread_blocking_adaptation</c-></code> or <code class="highlight"><c- kr>thread</c-><c- o>::</c-><c- n>blocking_adaptation</c-></code>.</p>
   </ol>
   <p>We recommend option #1, which had the support of the majority of the review group.</p>
   <p>If the committee feels strongly that a generic adapter for <code class="highlight"><c- n>blocking</c-><c- p>.</c-><c- n>always</c-></code> should exist, then we recommend both option #2 and option #3.</p>
   <h3 class="heading settled" data-level="5.3" id="movability"><span class="secno">5.3. </span><span class="content">Non-movable properties</span><a class="self-link" href="#movability"></a></h3>
   <p><a data-link-type="biblio" href="#biblio-p1393">[P1393]</a> does not require properties to be movable or copyable.  This was an intentional decision, and not an oversight.  While all the properties defined in P0443 are movable and copyable, user-defined executors may define custom properties that are not movable or copyable.  The executors framework, such as <code class="highlight"><c- n>any_executor</c-></code>, should work correctly with such properties.  That means any place that a generic property is passed as a parameter, it must be passed by <code class="highlight"><c- k>const</c-><c- o>&amp;</c-></code> and not by value.  We have identified these places that should be changed to handle non-movable properties:</p>
   <p>In <code class="highlight"><c- n>any_executor</c-></code>, the functions <code class="highlight"><c- n>query</c-></code>, <code class="highlight"><c- n>require</c-></code>, and <code class="highlight"><c- n>prefer</c-></code> accept a generic property by value.  They need to be changed to accept it by <code class="highlight"><c- k>const</c-><c- o>&amp;</c-></code>.  Using <code class="highlight"><c- n>require</c-></code> as an example:</p>
   <blockquote>
<pre class="highlight"><code class="highlight"><c- k><c- k>template</c-></c-> <c- o><c- o>&lt;</c-></c-><c- k><c- k>class</c-></c-> <c- nc><c- nc>Property</c-></c-><c- o><c- o>></c-></c->
<c- n><c- n>any_executor</c-></c-> <c- n><c- n>require</c-></c-><c- p><c- p>(</c-></c-><ins><c- k><c- k>const</c-></c-></ins> <c- n><c- n>Property</c-></c-><ins><c- o><c- o>&amp;</c-></c-></ins> <c- n><c- n>p</c-></c-><c- p><c- p>)</c-></c-> <c- k><c- k>const</c-></c-><c- p><c- p>;</c-></c->
</code></pre>
   </blockquote>
   <p>(We have heard that the <code class="highlight"><c- n>any_executor</c-></code> review group is recommending changing these functions to take the property argument by forwarding reference.  We are fine with that, and don’t believe that it would interfere with solving the non-movable property problem.)</p>
   <p><code class="highlight"><c- n>any_executor</c-></code>'s exposition-only <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> operation uses <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_convertible</c-></code> to find the appropriate property.  This operation won’t find non-movable properties because a non-movable type cannot be converted to itself.  The definition should be changed as follows:</p>
   <blockquote>
     In several places in this section the operation <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is used. All such uses mean the first type <code class="highlight"><c- n>P</c-></code> in the parameter pack <code class="highlight"><c- n>pn</c-></code> for which 
    <ins><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_same_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code> or</ins>
     <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_convertible_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code>. If no such type <code class="highlight"><c- n>P</c-></code> exists, the operation <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is ill-formed. 
   </blockquote>
   <p>Chris Kohlhoff has tested this and has found these changes to be necessary and sufficient to support non-movable properties in <code class="highlight"><c- n>any_executor</c-></code>.</p>
   <p>Changing <code class="highlight"><c- n>prefer_only</c-></code> to work with non-movable properties will be harder.  The specification for <code class="highlight"><c- n>prefer_only</c-></code> lists a public data member of the wrapper property type:</p>
   <blockquote>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>InnerProperty</c-><c- o>></c->
<c- k>struct</c-> <c- n>prefer_only</c->
<c- p>{</c->
  <c- n>InnerProperty</c-> <c- n>property</c-><c- p>;</c->
</pre>
   </blockquote>
   <p>The data member <code class="highlight"><c- n>property</c-></code> should be an exposition-only member, not part of the public interface of the class.  (If the public data member is intentional, then <code class="highlight"><c- n>prefer_only</c-></code> cannot support non-copyable properties.)  The <code class="highlight"><c- n>prefer_only</c-></code> constructor should state that it keeps a copy of the wrapped property if <code class="highlight"><c- n>InnerProperty</c-></code> is copyable, and that it keeps a reference to the wrapped property otherwise.</p>
   <p>Even though end users should never have to create <code class="highlight"><c- n>prefer_only</c-></code> objects (the end user only sees <code class="highlight"><c- n>prefer_only</c-></code> in the type list for <code class="highlight"><c- n>any_executor</c-></code>), the implementation of <code class="highlight"><c- n>any_executor</c-></code> likely needs to create temporary <code class="highlight"><c- n>prefer_only</c-></code> objects.  (Asio’s implementation of <code class="highlight"><c- n>any_executor</c-></code> creates such temporaries.)  Therefore, <code class="highlight"><c- n>prefer_only</c-></code>'s ability to support non-movable properties affects the usability of <code class="highlight"><c- n>any_executor</c-></code>.</p>
   <h3 class="heading settled" data-level="5.4" id="prefer"><span class="secno">5.4. </span><span class="content">Polymorphic executor wrappers and prefer-only properties</span><a class="self-link" href="#prefer"></a></h3>
   <p>The specification of customization point <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> in <a data-link-type="biblio" href="#biblio-p1393">[P1393]</a> only checks for functions named <code class="highlight"><c- n>require</c-></code>.  If requiring the property fails, then <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> returns the original executor unchanged.  The customization point never looks for functions named <code class="highlight"><c- n>prefer</c-></code>.</p>
   <p>(<code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> is supposed to return the original object unchanged if requiring the property fails.  But a wording bug in P1393 leaves out that fallback action.  There needs to be an extra bullet inserted between the fourth and fifth bullets, so it will be third from the end:</p>
   <blockquote>
    <ul>
     <li data-md>
      <ins>Otherwise, <code class="highlight"><c- n>E</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code>.</ins>
    </ul>
   </blockquote>
    This change must be made, even if the other proposed changes in this section are rejected.) 
   <p>This specification of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> makes it difficult for <code class="highlight"><c- n>any_executor</c-></code>, or any other generic code that forwards <code class="highlight"><c- n>require</c-></code> and <code class="highlight"><c- n>prefer</c-></code> operations on properties, to correctly handle a property that can be preferred but not required.</p>
   <p>As an example, assume that some property <code class="highlight"><c- n>prefer_nice_t</c-></code> defines <code class="highlight"><c- n>is_requirable</c-> <c- o>=</c-> false</code> and <code class="highlight"><c- n>is_preferable</c-> <c- o>=</c-> true</code>.  Assume that executor type <code class="highlight"><c- n>maybe_nice_exec</c-></code> supports the property <code class="highlight"><c- n>prefer_nice_t</c-></code>, such that given:</p>
<pre class="highlight"><c- n>maybe_nice_exec</c-> <c- n>e</c-> <c- o>=</c-> <c- p>...;</c->
<c- k>auto</c-> <c- n>nice_e</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>prefer_nice</c-><c- p>);</c->
</pre>
   <p>the executor <code class="highlight"><c- n>nice_e</c-></code> has the property <code class="highlight"><c- n>prefer_nice_t</c-></code>.</p>
   <p>Now assume that we wrap a <code class="highlight"><c- n>maybe_nice_exec</c-></code> in an <code class="highlight"><c- n>any_executor</c-></code> and try to do the same <code class="highlight"><c- n>prefer</c-></code> call:</p>
<pre class="highlight"><c- n>maybe_nice_exec</c-> <c- n>e</c-> <c- o>=</c-> <c- p>...;</c->
<c- n>any_executor</c-><c- o>&lt;</c-><c- n>prefer_nice_t</c-><c- o>></c-> <c- n>wrapped</c-><c- p>{</c-><c- n>e</c-><c- p>};</c->
<c- k>auto</c-> <c- n>nice_wrapped</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>wrapped</c-><c- p>,</c-> <c- n>prefer_nice</c-><c- p>);</c->
</pre>
   <p>Given the current specification of <code class="highlight"><c- n>any_executor</c-></code>, this code will not behave as expected. <code class="highlight"><c- n>nice_wrapped</c-></code> will not have the <code class="highlight"><c- n>prefer_nice_t</c-></code> property.  The call to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> will try to call <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>require</c-></code> member function.  The specification for that says:</p>
   <blockquote> <em>Returns</em>: A polymorphic wrapper whose target is the result of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>e</c-></code> is the target object of <code class="highlight"><c- o>*</c-><c- k>this</c-></code>. </blockquote>
    The call to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code> will fail immediately because <code class="highlight"><c- n>is_requirable</c-></code> is false.  The call will not be passed on to <code class="highlight"><c- n>maybe_nice_exec</c-></code> to be handled.  So the original <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> call will return the <code class="highlight"><c- n>any_executor</c-></code> unchanged rather than returning a new <code class="highlight"><c- n>any_executor</c-></code> whose target executor has the <code class="highlight"><c- n>prefer_nice_t</c-></code> property. 
   <p>To get the correct result, <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>require</c-></code> function has to call <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> instead of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-></code> when it was called by <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code>.  But it doesn’t have any foolproof way to know that it was called by <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> rather than <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-></code>.</p>
   <p>When generic code such as <code class="highlight"><c- n>any_executor</c-></code> is forwarding calls to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> from one object to a different object, it is not possible to forward the calls correctly because the important information of whether the original call was <code class="highlight"><c- n>require</c-></code> or <code class="highlight"><c- n>prefer</c-></code> is lost part way through the process.</p>
   <p>The review group recommends that this issue be fixed by changing the specification of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> in <a data-link-type="biblio" href="#biblio-p1393">[P1393]</a>, having it check for functions named <code class="highlight"><c- n>require</c-></code> first, then for functions named <code class="highlight"><c- n>prefer</c-></code>, then falling back to returning the object unchanged.</p>
   <blockquote>
     The name <code class="highlight"><c- n>prefer</c-></code> denotes a customization point object. The expression <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>,</c-> <c- n>Pn</c-><c- p>...)</c-></code> for some subexpressions <code class="highlight"><c- n>E</c-></code> and <code class="highlight"><c- n>P0</c-></code>, and where <code class="highlight"><c- n>Pn</c-><c- p>...</c-></code> represents <code class="highlight"><c- n>N</c-></code> subexpressions (where <code class="highlight"><c- n>N</c-></code> is 0 or more, and with types <code class="highlight"><c- n>T</c-> <c- o>=</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>E</c-><c- p>)</c-><c- o>></c-></code> and <code class="highlight"><c- n>Prop0</c-> <c- o>=</c-> <c- n>decay_t</c-><c- o>&lt;</c-><c- k>decltype</c-><c- p>(</c-><c- n>P0</c-><c- p>)</c-><c- o>></c-></code>) is expression-equivalent to: 
    <ul>
     <li data-md>
      <p>If <code class="highlight"><c- n>is_applicable_property_v</c-><c- o>&lt;</c-><c- n>T</c-><c- p>,</c-> <c- n>Prop0</c-><c- o>></c-> <c- o>&amp;&amp;</c-> <c- n>Prop0</c-><c- o>::</c-><c- n>is_preferable</c-></code> is not a well-formed constant expression with value <code class="highlight">true</code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>,</c-> <c- n>Pn</c-><c- p>...)</c-></code> is ill-formed.</p>
     <li data-md>
      <p>Otherwise, <code class="highlight"><c- n>E</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- n>Prop0</c-><c- o>::</c-><c- k>template</c-> <c- n>static_query_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>==</c-> <c- n>Prop0</c-><c- o>::</c-><c- n>value</c-><c- p>()</c-></code> is a well-formed constant expression with value <code class="highlight">true</code>.</p>
     <li data-md>
      <p>Otherwise, <code class="highlight"><c- p>(</c-><c- n>E</c-><c- p>).</c-><c- n>require</c-><c- p>(</c-><c- n>P0</c-><c- p>)</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- p>(</c-><c- n>E</c-><c- p>).</c-><c- n>require</c-><c- p>(</c-><c- n>P0</c-><c- p>)</c-></code> is a valid expression.</p>
     <li data-md>
      <p>Otherwise, <code class="highlight"><c- n>require</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>)</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- n>require</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>)</c-></code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code class="highlight"><c- n>require</c-></code> customization point object.</p>
     <li data-md>
      <ins>Otherwise, <code class="highlight"><c- p>(</c-><c- n>E</c-><c- p>).</c-><c- n>prefer</c-><c- p>(</c-><c- n>P0</c-><c- p>)</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- p>(</c-><c- n>E</c-><c- p>).</c-><c- n>prefer</c-><c- p>(</c-><c- n>P0</c-><c- p>)</c-></code> is a valid expression.</ins>
     <li data-md>
      <ins>Otherwise, <code class="highlight"><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>)</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>)</c-></code> is a valid expression with overload resolution performed in a context that does not include the declaration of the <code class="highlight"><c- n>prefer</c-></code> customization point object.</ins>
     <li data-md>
      <ins>Otherwise, <code class="highlight"><c- n>E</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>==</c-> <c- mi>0</c-></code>.</ins>
     <li data-md>
      <p>Otherwise, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>),</c-> <c- n>Pn</c-><c- p>...)</c-></code> if <code class="highlight"><c- n>N</c-> <c- o>></c-> <c- mi>0</c-></code> and the expression <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>),</c-> <c- n>Pn</c-><c- p>...)</c-></code> is a valid expression.</p>
     <li data-md>
      <p>Otherwise, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>E</c-><c- p>,</c-> <c- n>P0</c-><c- p>,</c-> <c- n>Pn</c-><c- p>...)</c-></code> is ill-formed.</p>
    </ul>
   </blockquote>
   <p>Along with this change, <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>prefer</c-></code> function should be changed from a non-member function to a member function.  The specification of the <code class="highlight"><c- n>prefer</c-></code> function doesn’t need to otherwise change.  (<a href="#movability">§ 5.3 Non-movable properties</a> and <a href="#find-prop">§ 5.5 any_executor's FIND_CONVERTIBLE_PROPERTY</a> suggest other changes to <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>prefer</c-></code> function, but those are separate issues.)</p>
   <p>Please note that only generic code that wants to correctly forward <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> calls will need to define a <code class="highlight"><c- n>prefer</c-></code> function.  The vast majority of executors or other property-aware classes will only need to define <code class="highlight"><c- n>require</c-></code> for the properties that they support.  That <code class="highlight"><c- n>require</c-></code> function will do the right thing for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-></code> for all normal property-aware classes.</p>
   <p>This is the preferred solution for <a data-link-type="biblio" href="#biblio-asio">[Asio]</a>, which has already implemented this change.</p>
   <h3 class="heading settled" data-level="5.5" id="find-prop"><span class="secno">5.5. </span><span class="content"><code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-></code></span><a class="self-link" href="#find-prop"></a></h3>
   <p>The type-erased executor wrapper <code class="highlight"><c- n>any_executor</c-></code> defines an exposition-only expression <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code>:</p>
   <blockquote> In several places in this section the operation <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is used. All such uses mean the first type <code class="highlight"><c- n>P</c-></code> in the parameter pack <code class="highlight"><c- n>pn</c-></code> for which <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>is_convertible_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code>. If no such type <code class="highlight"><c- n>P</c-></code> exists, the operation <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is ill-formed. </blockquote>
   <p>This exposition-only expression is used in the specification of <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>require</c-></code> function:</p>
   <blockquote>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>class</c-> <c- nc>Property</c-><c- o>></c->
<c- n>any_executor</c-> <c- n>require</c-><c- p>(</c-><c- n>Property</c-> <c- n>p</c-><c- p>)</c-> <c- k>const</c-><c- p>;</c->
</pre>
    <p><em>Remarks</em>: This function shall not participate in overload resolution unless <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-><c- p>(</c-><c- n>Property</c-><c- p>,</c-> <c- n>SupportableProperties</c-><c- p>)</c-><c- o>::</c-><c- n>is_requirable</c-></code> is well-formed and has the value <code class="highlight">true</code>.</p>
    <p><em>Returns</em>: A polymorphic wrapper whose target is the result of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>e</c-></code> is the target object of <code class="highlight"><c- o>*</c-><c- k>this</c-></code>.</p>
   </blockquote>
   <p>Consider this example:</p>
<pre class="highlight"><c- n>any_executor</c-><c- o>&lt;</c-><c- n>blocking_t</c-><c- p>,</c-> <c- n>blocking_t</c-><c- o>::</c-><c- n>never_t</c-><c- o>></c-> <c- n>ex</c-><c- p>{</c-><c- n>my_executor</c-><c- p>};</c->
<c- n>ex</c-><c- p>.</c-><c- n>require</c-><c- p>(</c-><c- n>blocking</c-><c- p>.</c-><c- n>never</c-><c- p>);</c->
</pre>
   <p>The <code class="highlight"><c- n>ex</c-><c- p>.</c-><c- n>require</c-><c- p>(</c-><c- n>blocking</c-><c- p>.</c-><c- n>never</c-><c- p>)</c-></code> call is ill-formed. <code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-></code> finds <code class="highlight"><c- n>blocking_t</c-></code>, because it is the first one in the list that is convertible from a <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>never_t</c-></code>.  But <code class="highlight"><c- n>blocking_t</c-><c- o>::</c-><c- n>is_requirable</c-></code> is false, so this particular overload of <code class="highlight"><c- n>require</c-></code> doesn’t participate in overload resolution.  (This is not a contrived example.  This pattern is in the first <code class="highlight"><c- n>any_executor</c-></code> <a href="#examples-any-executor">example</a> in this paper.)</p>
   <p>The fix is to check for <code class="highlight"><c- n>is_convertible</c-></code> and <code class="highlight"><c- n>is_requirable</c-></code> at the same time, rather than checking <code class="highlight"><c- n>is_convertible</c-></code> first and <code class="highlight"><c- n>is_requirable</c-></code> later.  The specification of <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>require</c-></code> becomes (with the change from <a href="#movability">§ 5.3 Non-movable properties</a> thrown in):</p>
   <blockquote>
<pre class="highlight"><code class="highlight"><c- k><c- k>template</c-></c-> <c- o><c- o>&lt;</c-></c-><c- k><c- k>class</c-></c-> <c- nc><c- nc>Property</c-></c-><c- o><c- o>></c-></c->
<c- n><c- n>any_executor</c-></c-> <c- n><c- n>require</c-></c-><c- p><c- p>(</c-></c-><ins><c- k><c- k>const</c-></c-></ins> <c- n><c- n>Property</c-></c-><ins><c- o><c- o>&amp;</c-></c-></ins> <c- n><c- n>p</c-></c-><c- p><c- p>)</c-></c-> <c- k><c- k>const</c-></c-><c- p><c- p>;</c-></c->
</code></pre>
    <div class="ins">
      Let <code class="highlight"><c- n>FIND_REQUIRABLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> be the first type <code class="highlight"><c- n>P</c-></code> in the parameter pack <code class="highlight"><c- n>pn</c-></code> for which 
     <ul>
      <li data-md>
       <p><code class="highlight"><c- n>is_same_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code> or <code class="highlight"><c- n>is_convertible_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code>, and</p>
      <li data-md>
       <p><code class="highlight"><c- n>P</c-><c- o>::</c-><c- n>is_requirable</c-></code> is <code class="highlight">true</code>.</p>
     </ul>
     <p>If no such <code class="highlight"><c- n>P</c-></code> exists, the operation <code class="highlight"><c- n>FIND_REQUIRABLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is ill-formed.</p>
    </div>
    <p>
     <em>Remarks</em>: This function shall not participate in overload resolution unless 
     <del><code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-></code></del>
     <ins><code class="highlight"><c- n>FIND_REQUIRABLE_PROPERTY</c-></code></ins>
     <code class="highlight"><c- p>(</c-><c- n>Property</c-><c- p>,</c-> <c- n>SupportableProperties</c-><c- p>)</c-></code>
     <del><code class="highlight"><c- o>::</c-><c- n>is_requirable</c-></code></del>
      is well-formed 
     <del>and has the value <code class="highlight">true</code></del>
     .
    </p>
    <p><em>Returns</em>: A polymorphic wrapper whose target is the result of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>e</c-></code> is the target object of <code class="highlight"><c- o>*</c-><c- k>this</c-></code>.</p>
   </blockquote>
   <p>A similar change also needs to be made to <code class="highlight"><c- n>any_executor</c-></code>'s <code class="highlight"><c- n>prefer</c-></code> function.  Combining this change with the one from <a href="#movability">§ 5.3 Non-movable properties</a> and changing the function from a non-member to a member as described in <a href="#prefer">§ 5.4 Polymorphic executor wrappers and prefer-only properties</a>, the specification becomes:</p>
   <blockquote>
<pre class="highlight"><code class="highlight"><c- k><c- k>template</c-></c-> <c- o><c- o>&lt;</c-></c-><c- k><c- k>class</c-></c-> <c- nc><c- nc>Property</c-></c-><del><c- p><c- p>,</c-></c-> <c- n><c- n>class</c-></c-><c- p><c- p>...</c-></c-> <c- n><c- n>SupportableProperties</c-></c-></del><c- o><c- o>></c-></c->
<c- n><c- n>any_executor</c-></c-> <c- n><c- n>prefer</c-></c-><c- p><c- p>(</c-></c-><del><c- k><c- k>const</c-></c-> <c- n><c- n>any_executor</c-></c-><c- o><c- o>&lt;</c-></c-><c- n><c- n>SupportableProperties</c-></c-><c- p><c- p>...</c-></c-><c- o><c- o>>&amp;</c-></c-> <c- n><c- n>e</c-></c-><c- p><c- p>,</c-></c-></del> <ins><c- k><c- k>const</c-></c-></ins> <c- n><c- n>Property</c-></c-><ins><c- o><c- o>&amp;</c-></c-></ins> <c- n><c- n>p</c-></c-><c- p><c- p>);</c-></c->
</code></pre>
    <div class="ins">
      Let <code class="highlight"><c- n>FIND_PREFERABLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> be the first type <code class="highlight"><c- n>P</c-></code> in the parameter pack <code class="highlight"><c- n>pn</c-></code> for which 
     <ul>
      <li data-md>
       <p><code class="highlight"><c- n>is_same_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code> or <code class="highlight"><c- n>is_convertible_v</c-><c- o>&lt;</c-><c- n>p</c-><c- p>,</c-> <c- n>P</c-><c- o>></c-></code> is <code class="highlight">true</code>, and</p>
      <li data-md>
       <p><code class="highlight"><c- n>P</c-><c- o>::</c-><c- n>is_preferable</c-></code> is <code class="highlight">true</code>.</p>
     </ul>
     <p>If no such <code class="highlight"><c- n>P</c-></code> exists, the operation <code class="highlight"><c- n>FIND_PREFERABLE_PROPERTY</c-><c- p>(</c-><c- n>p</c-><c- p>,</c-> <c- n>pn</c-><c- p>)</c-></code> is ill-formed.</p>
    </div>
    <p>
     <em>Remarks</em>: This function shall not participate in overload resolution unless 
     <del><code class="highlight"><c- n>FIND_CONVERTIBLE_PROPERTY</c-></code></del>
     <ins><code class="highlight"><c- n>FIND_PREFERABLE_PROPERTY</c-></code></ins>
     <code class="highlight"><c- p>(</c-><c- n>Property</c-><c- p>,</c-> <c- n>SupportableProperties</c-><c- p>)</c-></code>
     <del><code class="highlight"><c- o>::</c-><c- n>is_preferable</c-></code></del>
      is well-formed 
     <del>and has the value <code class="highlight">true</code></del>
     .
    </p>
    <p><em>Returns</em>: A polymorphic wrapper whose target is the result of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>prefer</c-><c- p>(</c-><c- n>e</c-><c- p>,</c-> <c- n>p</c-><c- p>)</c-></code>, where <code class="highlight"><c- n>e</c-></code> is the target object of <code class="highlight"><c- o>*</c-><c- k>this</c-></code>.</p>
   </blockquote>
   <h3 class="heading settled" data-level="5.6" id="any-executor-target"><span class="secno">5.6. </span><span class="content"><code class="highlight"><c- n>any_executor</c-><c- o>&lt;</c-><c- n>P</c-><c- p>...</c-><c- o>>::</c-><c- n>target</c-></code> causes unused RTTI overhead</span><a class="self-link" href="#any-executor-target"></a></h3>
   <p>The member functions <code class="highlight"><c- n>target</c-></code> and <code class="highlight"><c- n>target_type</c-></code> of <code class="highlight"><c- n>any_executor</c-></code> cause the generation of RTTI for every executor type that is potentially wrapped in an <code class="highlight"><c- n>any_executor</c-></code>.  This RTTI overhead is present even if <code class="highlight"><c- n>target</c-></code> and <code class="highlight"><c- n>target_type</c-></code> are never called because <code class="highlight"><c- n>target_type</c-></code> is a non-template member function.  Some users will likely object to the RTTI overhead as going against C++ principle of "What you don’t use, you don’t pay for."</p>
   <p>Using a property rather than a member function to retrieve the target executor from an <code class="highlight"><c- n>any_executor</c-></code> reduces the RTTI to situations where the target is actually retrieved.  The property can be user-defined and doesn’t have to be part of the <code class="highlight"><c- n>any_executor</c-></code> specification:</p>
<pre class="highlight"><c- k>struct</c-> <c- n>target_property_t</c->
<c- p>{</c->
    <c- k>using</c-> <c- n>polymorphic_query_result_type</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>any</c-><c- p>;</c->

    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_requirable</c-> <c- o>=</c-> false<c- p>;</c->
    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_preferable</c-> <c- o>=</c-> false<c- p>;</c->

    <c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Ex</c-><c- o>></c->
    <c- k>static</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_applicable_property_v</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>executor</c-><c- o>&lt;</c-><c- n>Ex</c-><c- o>></c-><c- p>;</c->
<c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Executor</c-><c- o>></c->
<c- k>struct</c-> <c- nl>is_polymorphic_executor</c-> <c- p>:</c-> <c- n>std</c-><c- o>::</c-><c- n>false_type</c-> <c- p>{};</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- p>...</c-><c- n>Ps</c-><c- o>></c->
<c- k>struct</c-> <c- n>is_polymorphic_executor</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>any_executor</c-><c- o>&lt;</c-><c- n>Ps</c-><c- p>...</c-><c- o>>></c-> <c- o>:</c-> <c- n>std</c-><c- o>::</c-><c- n>true_type</c-> <c- p>{};</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Executor</c-><c- o>></c->
<c- kr>inline</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_polymorphic_executor_v</c-> <c- o>=</c-> <c- n>is_polymorphic_executor</c-><c- o>&lt;</c-><c- n>Executor</c-><c- o>>::</c-><c- n>value</c-><c- p>;</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- n>Executor</c-><c- o>></c->
<c- n>std</c-><c- o>::</c-><c- n>any</c-> <c- n>query</c-><c- p>(</c-><c- n>Executor</c-> <c- n>ex</c-><c- p>,</c-> <c- n>target_property_t</c-><c- p>)</c->
<c- p>{</c->
    <c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>is_polymorphic_executor_v</c-><c- o>&lt;</c-><c- n>Executor</c-><c- o>></c-><c- p>,</c->
        <c- s>"tried to query the target of a polymorphic executor which does not support target_property_t"</c-><c- p>);</c->
    <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>any</c-><c- p>(</c-><c- n>ex</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>(This proof of concept, with some example code of how to use it, can be found <a href="https://github.com/griwes/asio/commit/3a2df4745fbaab2dfc769530a69751e85f397e6c">here</a>.)</p>
   <p>If the committee is not overly concerned about the RTTI overhead, the specification can be left unchanged.  If the committee likes this approach of using a property to retrieve the target executor, then the <code class="highlight"><c- n>target</c-></code> and <code class="highlight"><c- n>target_info</c-></code> members of <code class="highlight"><c- n>any_executor</c-></code> should be removed and the target property can either be made a standard property or left to the user to define.  The review group is not making any particular recommendation on this matter.</p>
   <h3 class="heading settled" data-level="5.7" id="bulk_guarantee"><span class="secno">5.7. </span><span class="content"><code class="highlight"><c- n>bulk_guarantee</c-></code> specification should match execution policies</span><a class="self-link" href="#bulk_guarantee"></a></h3>
   <p>The specification <code class="highlight"><c- n>bulk_guarantee_t</c-></code> in section 2.2.12.5 lists three possible values:</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>bulk_guarantee</c-><c- p>.</c-><c- n>unsequenced</c-></code>: Execution agents within the same bulk execution may be parallelized and vectorized.</p>
    <li data-md>
     <p><code class="highlight"><c- n>bulk_guarantee</c-><c- p>.</c-><c- n>sequenced</c-></code>: Execution agents within the same bulk execution may not be parallelized.</p>
    <li data-md>
     <p><code class="highlight"><c- n>bulk_guarantee</c-><c- p>.</c-><c- n>parallel</c-></code>: Execution agents within the same bulk execution may be parallelized.</p>
   </ul>
   <p>These correspond in some ways to the <a href="http://wg21.link/execpol">execution policies</a> for parallel algorithms, except that there are four execution policies, and <code class="highlight"><c- n>bulk_guarantee</c-><c- p>.</c-><c- n>unsequenced</c-></code> seems to correspond to <code class="highlight"><c- n>parallel_unsequenced_policy</c-></code> rather than <code class="highlight"><c- n>unsequenced_policy</c-></code>.</p>
   <p>The relationship between the <code class="highlight"><c- n>bulk_guarantee</c-></code> property and the execution policies needs to be better defined.  Any differences between them needs to be clearly explained.  (At least in P0443, if not in the text of the standard.)  The review group believes this is an issue that the authors of P0443 need to address.  They are better equipped to come up with the right wording than either the review group or LEWG.</p>
   <p>Daisy Hollman thinks it could be helpful to move the specification of <code class="highlight"><c- n>bulk_guarantee</c-></code> to a separate paper, because a proper treatment is a paper-length topic and any hand-waving could be harmful to eventual success.</p>
   <h3 class="heading settled" data-level="5.8" id="established"><span class="secno">5.8. </span><span class="content">What does "established property" mean?</span><a class="self-link" href="#established"></a></h3>
   <p>Many places in the paper use the phrase "property already established" or something similar.  But there is no precise definition of what "established" means.  The paper should provide a definition, so that implementations (and users who write their own executor types) have a better understanding of what to implement.</p>
   <p>Two obvious possible definitions of an established property might be:</p>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>prop</c-><c- p>)</c-> <c- o>==</c-> <c- n>prop_value</c-></code> is true.</p>
    <li data-md>
     <p><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>require</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>prop</c-><c- p>)</c-> <c- o>==</c-> <c- n>ex</c-></code> is true (i.e. requiring the property has no effect).</p>
   </ol>
   <p>Both of those definitions have flaws, and don’t work correctly in all situations.  We don’t have a good suggestion of what the definition of an established property should be.  Like the previous issue, we think this is something that the P0443 authors need to address.</p>
   <p>(We have heard that the <code class="highlight"><c- n>static_thread_pool</c-></code> review group is also suggesting how to define or reword "established property", at least for its uses in <code class="highlight"><c- n>static_thread_pool</c-></code>.  There may be overlap in this area.)</p>
   <h3 class="heading settled" data-level="5.9" id="allocator-value"><span class="secno">5.9. </span><span class="content"><code class="highlight"><c- n>allocator_t</c-><c- o>::</c-><c- n>value</c-></code> should not be static</span><a class="self-link" href="#allocator-value"></a></h3>
   <p>Section 2.2.13.1 "<code class="highlight"><c- n>allocator_t</c-></code> members" states:</p>
   <blockquote>
     <code class="highlight"><c- k>static</c-> <c- k>constexpr</c-> <c- n>ProtoAllocator</c-> <c- nf>value</c-><c- p>()</c-> <c- k>const</c-><c- p>;</c-></code> 
    <p><em>Returns:</em> The exposition-only member <code class="highlight"><c- n>a_</c-></code>.</p>
   </blockquote>
   <p><code class="highlight"><c- n>value</c-></code> is <code class="highlight"><c- k>static</c-></code>, but the exposition-only member <code class="highlight"><c- n>a_</c-></code> is not.  A static member function cannot access a non-static data member.</p>
   <p>We think the correct fix is to change <code class="highlight"><c- n>value</c-></code> to be a non-static member function.  One purpose of the <code class="highlight"><c- n>allocator</c-></code> property is to get an executor object to use a particular allocator object.  The <code class="highlight"><c- n>allocator</c-></code> property needs to store that particular allocator object, so there is not always a generic value that can be returned by a static <code class="highlight"><c- n>value</c-></code> function.</p>
   <h3 class="heading settled" data-level="5.10" id="context"><span class="secno">5.10. </span><span class="content"><code class="highlight"><c- n>context</c-></code> property has no constraints</span><a class="self-link" href="#context"></a></h3>
   <p>The <code class="highlight"><c- n>context</c-></code> property is a query-only property that can be used to get the execution context for an executor.  For example, querying the <code class="highlight"><c- n>context</c-></code> of an executor that came from a <code class="highlight"><c- n>static_thread_pool</c-></code> will return the <code class="highlight"><c- n>static_thread_pool</c-></code> object that created the executor.</p>
   <p>The issue is that there are no requirements on the type or the value of the result of querying the <code class="highlight"><c- n>context</c-></code> property. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>query</c-><c- p>(</c-><c- n>ex</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>context</c-><c- p>)</c-></code> can be any type and doesn’t have to satisfy any particular concept.  This makes the <code class="highlight"><c- n>context</c-></code> property difficult to use in generic code.  It is only really useful in code that knows something about the type of executor that it is working with.</p>
   <p>We are not proposing that P0443 be changed to deal with this, since we didn’t think of any way to improve the situation.  We are just raising this as an issue to be aware of.</p>
  </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="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-asio">[Asio]
   <dd>Chris Kohlhoff. <a href="https://github.com/chriskohlhoff/asio/tree/asio-1-17-0">Asio C++ library</a>. URL: <a href="https://github.com/chriskohlhoff/asio/tree/asio-1-17-0">https://github.com/chriskohlhoff/asio/tree/asio-1-17-0</a>
   <dt id="biblio-p0443r13">[P0443R13]
   <dd><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0443r13.html">A Unified Executors Proposal for C++</a>. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0443r13.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0443r13.html</a>
   <dt id="biblio-p1393">[P1393]
   <dd><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1393r0.html">A General Property Customization Mechanism</a>. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1393r0.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1393r0.html</a>
   <dt id="biblio-p2033">[P2033]
   <dd>Jared Hoberock. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2033r0.pdf">History of Executor Properties</a>. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2033r0.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2033r0.pdf</a>
  </dl>