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

/* color variables included separately for reliability */

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

	html {
	}

	body {
		counter-reset: example figure issue;

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	p {
		margin: 1em 0;
	}

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

	/* Do something nice. */

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

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

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

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

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

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

	img {
		border-style: none;
	}

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


/*
Alternate table alignment rules

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

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

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

Possible extra rowspan handling

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

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

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


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

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

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

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

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

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

		.toc li {
			clear: both;
		}

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.outdated-warning span {
	display: block;
}

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

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

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

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

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



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

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

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

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

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			* http://lea.verou.me/2012/04/background-attachment-local/
			*
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
						top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
						top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style>
    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 fb1e763a4, updated Tue Mar 1 13:13:50 2022 -0800" name="generator">
  <link href="https://wg21.link/p2408r5" 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: var(--a-normal-text);
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

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

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

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

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

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

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

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

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

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

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

    --heading-text: #005a9c;

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

    --algo-border: #def;

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

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

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

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

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

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

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

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

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

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

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

    --datacell-border: silver;

    --indexinfo-text: #707070;

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

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

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

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

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

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

            #hidedel:checked ~ del, #hidedel:checked ~ * del { display:none; }
            #hidedel ~ #hidedel-label::before, #hidedel ~ * #hidedel-label::before { content: "☐ "; }
            #hidedel:checked ~ #hidedel-label::before, #hidedel:checked ~ * #hidedel-label::before { content: "☑ "; }
        </style>
<style>/* style-issues */

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

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

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

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

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

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

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

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

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

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

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

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

        --heading-text: #8af;

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

        --algo-border: #456;

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

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

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

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

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

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

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

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

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

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

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

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

        --datacell-border: silver;

        --indexinfo-text: #aaa;

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

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

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

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

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <input id="hidedel" style="display:none" type="checkbox">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P2408R5<br>Ranges iterators as inputs to non-Ranges algorithms</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal, <time class="dt-updated" datetime="2022-04-22">2022-04-22</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://wg21.link/p2408r5">https://wg21.link/p2408r5</a>
     <dt class="editor">Author:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:dolsen@nvidia.com">David Olsen</a> (<span class="p-org org">NVIDIA</span>)
     <dt>Audience:
     <dd>WG21
     <dt>Toggle Diffs:
     <dd>
      <label for="hidedel" id="hidedel-label">Hide deleted text</label>
     <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="#abstract"><span class="secno">1</span> <span class="content">Abstract</span></a>
    <li>
     <a href="#revisions"><span class="secno">2</span> <span class="content">Revision history</span></a>
     <ol class="toc">
      <li><a href="#r0"><span class="secno">2.1</span> <span class="content">R0</span></a>
      <li><a href="#r1"><span class="secno">2.2</span> <span class="content">R1</span></a>
      <li><a href="#r2"><span class="secno">2.3</span> <span class="content">R2</span></a>
      <li><a href="#r3"><span class="secno">2.4</span> <span class="content">R3</span></a>
      <li><a href="#r4"><span class="secno">2.5</span> <span class="content">R4</span></a>
      <li><a href="#r5"><span class="secno">2.6</span> <span class="content">R5</span></a>
     </ol>
    <li><a href="#motivation"><span class="secno">3</span> <span class="content">Motivation</span></a>
    <li>
     <a href="#analysis"><span class="secno">4</span> <span class="content">Analysis</span></a>
     <ol class="toc">
      <li><a href="#current-impl"><span class="secno">4.1</span> <span class="content">Current situation</span></a>
     </ol>
    <li>
     <a href="#solutions"><span class="secno">5</span> <span class="content">Possible Solutions</span></a>
     <ol class="toc">
      <li><a href="#no-action"><span class="secno">5.1</span> <span class="content">Do nothing</span></a>
      <li><a href="#change-existing"><span class="secno">5.2</span> <span class="content">Relax the <i>Cpp17</i> iterator requirements</span></a>
      <li><a href="#require-concept"><span class="secno">5.3</span> <span class="content">Algorithms require concepts instead of categories</span></a>
     </ol>
    <li>
     <a href="#impact"><span class="secno">6</span> <span class="content">Impact and Details</span></a>
     <ol class="toc">
      <li><a href="#changes"><span class="secno">6.1</span> <span class="content">Changes</span></a>
      <li><a href="#relaxed"><span class="secno">6.2</span> <span class="content">Relaxed requirements</span></a>
      <li><a href="#elsewhere"><span class="secno">6.3</span> <span class="content">Other uses</span></a>
      <li><a href="#impl-impact"><span class="secno">6.4</span> <span class="content">Implementation impact</span></a>
      <li><a href="#user-impact"><span class="secno">6.5</span> <span class="content">User impact</span></a>
     </ol>
    <li><a href="#mutable"><span class="secno">7</span> <span class="content">Mutable Iterators and Proxy Iterators</span></a>
    <li><a href="#sentinels"><span class="secno">8</span> <span class="content">Sentinels</span></a>
    <li><a href="#experience"><span class="secno">9</span> <span class="content">Implementation Experience</span></a>
    <li><a href="#feature-macro"><span class="secno">10</span> <span class="content">Feature Test Macro</span></a>
    <li><a href="#wording"><span class="secno">11</span> <span class="content">Wording</span></a>
    <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="abstract"><span class="secno">1. </span><span class="content">Abstract</span><a class="self-link" href="#abstract"></a></h2>
   <p>Change the iterator requirements for non-Ranges algorithms.  For forward iterators and above that are constant iterators, instead of requiring that iterators meet certain <em>Cpp17...Iterator</em> requirements, require that the iterators model certain iterator concepts.  This makes iterators from several standard views usable with non-Ranges algorithms that require forward iterators or above, such as the parallel overloads of most algorithms.</p>
   <h2 class="heading settled" data-level="2" id="revisions"><span class="secno">2. </span><span class="content">Revision history</span><a class="self-link" href="#revisions"></a></h2>
   <h3 class="heading settled" data-level="2.1" id="r0"><span class="secno">2.1. </span><span class="content">R0</span><a class="self-link" href="#r0"></a></h3>
   <p>This paper arose out of a private e-mail discussion where Bryce Adelstein Lelbach questioned why code that is similar to the first example in <a href="#motivation">§ 3 Motivation</a> didn’t compile with MSVC.</p>
   <h3 class="heading settled" data-level="2.2" id="r1"><span class="secno">2.2. </span><span class="content">R1</span><a class="self-link" href="#r1"></a></h3>
   <p>Add the section <a href="#sentinels">§ 8 Sentinels</a> based on <a href="https://wiki.edg.com/bin/view/Wg21telecons2021/P2408r0-20210809">discussion</a> in SG9 (Ranges) on 9 Aug 2021.  This is just background information; there is no change to what is being proposed.</p>
   <h3 class="heading settled" data-level="2.3" id="r2"><span class="secno">2.3. </span><span class="content">R2</span><a class="self-link" href="#r2"></a></h3>
   <p>Change the title from "Ranges views as inputs to non-Ranges algorithms" to "Ranges iterators as inputs to non-Ranges algorithms".</p>
   <p>Based on <a href="https://wiki.edg.com/bin/view/Wg21telecons2021/P2408#SG9-2021-09-13">discussion</a> in SG9 (Ranges) on 13 Sep 2021, withdraw the portion of the paper that changed input iterators and output iterators to use iterator concepts.  The requirements for input and output iterators remain unchanged from the current standard, using <em>Cpp17Iterator</em> requirements.</p>
   <p>Add the section <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2408r2.html#mutable">Mutable Iterators</a>.  This is just background information; there is no change to what is being proposed.</p>
   <p>In <a href="#analysis">§ 4 Analysis</a>, discuss the iterators for <code class="highlight"><c- n>zip_view</c-></code>, et al., that are being proposed in <a data-link-type="biblio" href="#biblio-p2321">[P2321]</a>.</p>
   <h3 class="heading settled" data-level="2.4" id="r3"><span class="secno">2.4. </span><span class="content">R3</span><a class="self-link" href="#r3"></a></h3>
   <p>Based on discussion in SG9 (Ranges) on 11 Oct 2021, change the proposal to handle proxy iterators correctly.  This turned out to be a significant change, both to the wording and to the design section.  In the wording, the change from <em>Cpp17...Iterator</em> requirements to iterator concepts now only happens for constant iterators, not all iterators.  In the design section, <a href="#require-concept">§ 5.3 Algorithms require concepts instead of categories</a> and <a href="#impact">§ 6 Impact and Details</a> had significant changes and <a href="#mutable">§ 7 Mutable Iterators and Proxy Iterators</a> was completely rewritten.</p>
   <h3 class="heading settled" data-level="2.5" id="r4"><span class="secno">2.5. </span><span class="content">R4</span><a class="self-link" href="#r4"></a></h3>
   <p>Gather implementation experience, described in <a href="#experience">§ 9 Implementation Experience</a>.  Update the <a href="#impl-impact">§ 6.4 Implementation impact</a> section based on the implementation experience.</p>
   <h3 class="heading settled" data-level="2.6" id="r5"><span class="secno">2.6. </span><span class="content">R5</span><a class="self-link" href="#r5"></a></h3>
   <p>Removed the issue about using "shall" for uncheckable requirements on user code based on discussion in LWG on 2022-04-22.  I had thought it was an issue because I was not aware that Library has a different meaning for "shall" than Core does.</p>
   <h2 class="heading settled" data-level="3" id="motivation"><span class="secno">3. </span><span class="content">Motivation</span><a class="self-link" href="#motivation"></a></h2>
   <p>These two snippets of code should be well-formed:</p>
<pre class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>data</c-> <c- o>=</c-> <c- p>...;</c->
<c- k>auto</c-> <c- n>v</c-> <c- o>=</c-> <c- n>data</c-> <c- o>|</c-> <c- n>std</c-><c- o>::</c-><c- n>views</c-><c- o>::</c-><c- n>transform</c-><c- p>([](</c-><c- b>int</c-> <c- n>x</c-><c- p>){</c-> <c- k>return</c-> <c- n>x</c-> <c- o>*</c-> <c- n>x</c-><c- p>;</c-> <c- p>});</c->
<c- b>int</c-> <c- n>sum_of_squares</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>reduce</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>par</c-><c- p>,</c-> <c- n>begin</c-><c- p>(</c-><c- n>v</c-><c- p>),</c-> <c- n>end</c-><c- p>(</c-><c- n>v</c-><c- p>));</c->
</pre>
<pre class="highlight"><c- k>auto</c-> <c- n>idxs</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>views</c-><c- o>::</c-><c- n>iota</c-><c- p>(</c-><c- mi>0</c-><c- p>,</c-> <c- n>N</c-><c- p>);</c->
<c- n>std</c-><c- o>::</c-><c- n>transform</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>execution</c-><c- o>::</c-><c- n>par</c-><c- p>,</c-> <c- n>begin</c-><c- p>(</c-><c- n>idxs</c-><c- p>),</c-> <c- n>end</c-><c- p>(</c-><c- n>idxs</c-><c- p>),</c-> <c- n>begin</c-><c- p>(</c-><c- n>sqrts</c-><c- p>),</c->
               <c- p>[](</c-><c- b>int</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>std</c-><c- o>::</c-><c- n>sqrt</c-><c- p>(</c-><c- b>float</c-><c- p>(</c-><c- n>x</c-><c- p>));</c-> <c- p>});</c->
</pre>
   <p>It should be possible, in most cases, to use the iterators from ranges and views as the inputs to C++17 parallel algorithms and to other algorithms that require forward iterators or greater.</p>
   <h2 class="heading settled" data-level="4" id="analysis"><span class="secno">4. </span><span class="content">Analysis</span><a class="self-link" href="#analysis"></a></h2>
   <p><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>reduce</c-></code> requires that its iterator parameters satisfy the requirements of <em>Cpp17ForwardIterator</em>.  One of those requirements is that <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>iterator_traits</c-><c- o>&lt;</c-><c- n>I</c-><c- o>>::</c-><c- n>reference</c-></code> be a reference type, either <code class="highlight"><c- n>T</c-><c- o>&amp;</c-></code> or <code class="highlight"><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-></code>.  (<a href="http://eel.is/c++draft/iterator.cpp17#forward.iterators-1.3">[forward.iterators]/p1.3</a>)  The iterator category of <code class="highlight"><c- n>transform_view</c-><c- o>::</c-><c- n>iterator</c-></code> matches the iterator category of the underlying range’s iterator only if the transformation function returns an lvalue reference.  If the return type of the transformation function is a value rather than a reference, the iterator category of <code class="highlight"><c- n>transform_view</c-><c- o>::</c-><c- n>iterator</c-></code> is <code class="highlight"><c- n>input_iterator_tag</c-></code>, because the iterator’s <code class="highlight"><c- n>reference</c-></code> type alias can’t be a reference type.  (<a href="http://eel.is/c++draft/range.transform.iterator#2">[range.transform.iterator]/p2</a>)</p>
   <p>In this example, the lambda transformation function returns a value, so the iterators passed to <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>reduce</c-></code> are only input iterators in the classic iterator taxonomy used by the non-Ranges algorithms, even though the iterators satisfy the <code class="highlight"><c- n>random_access_iterator</c-></code> concept in the Ranges iterator taxonomy.</p>
   <p>Several other views have the same issue, where the iterator category of the view’s iterator is <code class="highlight"><c- n>input_iterator_tag</c-></code> even when the iterator concept is something else.</p>
   <ul>
    <li data-md>
     <p><code class="highlight"><c- n>iota_view</c-><c- o>::</c-><c- n>iterator</c-></code>'s iterator category is always <code class="highlight"><c- n>input_iterator_tag</c-></code> while its iterator concept is often <code class="highlight"><c- n>random_access_iterator_tag</c-></code>. <a href="http://eel.is/c++draft/range.iota.iterator">[range.iota.iterator]</a></p>
    <li data-md>
     <p><code class="highlight"><c- n>lazy_split_view</c-><c- o>::</c-><c- n>iterator</c-></code>'s iterator category is always <code class="highlight"><c- n>input_iterator_tag</c-></code> while its iterator concept is <code class="highlight"><c- n>forward_iterator_tag</c-></code> if the underlying range is a forward range. <a href="http://eel.is/c++draft/range.lazy.split.outer">[range.lazy.split.outer]</a></p>
    <li data-md>
     <p><code class="highlight"><c- n>split_view</c-><c- o>::</c-><c- n>iterator</c-></code>'s iterator category is always <code class="highlight"><c- n>input_iterator_tag</c-></code> and its iterator concept is always <code class="highlight"><c- n>forward_iterator_tag</c-></code>. <a href="http://eel.is/c++draft/range.split.iterator">[range.split.iterator]</a></p>
    <li data-md>
     <p><code class="highlight"><c- n>elements_view</c-><c- o>::</c-><c- n>iterator</c-></code> is similar to <code class="highlight"><c- n>transform_view</c-><c- o>::</c-><c- n>iterator</c-></code> in that the iterator category depends on the value category of the return type of the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>get</c-><c- o>&lt;</c-><c- n>N</c-><c- o>></c-></code> function used to extract the element.  The iterator category is <code class="highlight"><c- n>input_iterator_tag</c-></code> if <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>get</c-><c- o>&lt;</c-><c- n>N</c-><c- o>></c-></code> returns an rvalue, and (mostly) matches the iterator category of the base range’s iterator otherwise.  The iterator concept depends only on the base range’s iterator, not on the <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>get</c-><c- o>&lt;</c-><c- n>N</c-><c- o>></c-></code> function. <a href="http://eel.is/c++draft/range.elements#iterator-2">[range.elements.iterator]/p2</a></p>
    <li data-md>
     <p>In <a data-link-type="biblio" href="#biblio-p2321">[P2321]</a>, the iterators for <code class="highlight"><c- n>zip_view</c-></code> and <code class="highlight"><c- n>adjacent_view</c-></code> have an iterator category of <code class="highlight"><c- n>input_iterator_tag</c-></code> but an iterator concept that matches the lowest iterator concept of the iterators of the underlying ranges.  The iterators for <code class="highlight"><c- n>zip_transform_view</c-></code> and <code class="highlight"><c- n>adjacent_transform_view</c-></code> determine their category and concept similar to how it is done for <code class="highlight"><c- n>transform_view</c-><c- o>::</c-><c- n>iterator</c-></code>.</p>
   </ul>
   <h3 class="heading settled" data-level="4.1" id="current-impl"><span class="secno">4.1. </span><span class="content">Current situation</span><a class="self-link" href="#current-impl"></a></h3>
   <p>MSVC checks that iterator arguments to parallel algorithms have the correct iterator category.  If either of the code snippets in <a href="#motivation">§ 3 Motivation</a> are compiled, the compilation will fail with "error C2338: Parallel algorithms require forward iterators or stronger."</p>
   <p>libstd++ does not do any up-front checking of the iterator category of algorithm arguments.  Its implementation of algorithms will accept iterators of any category as long as the iterators support the operations that are actually used in the implementation.  The code snippets in <a href="#motivation">§ 3 Motivation</a> can be successfully compiled with GCC 11.1.</p>
   <h2 class="heading settled" data-level="5" id="solutions"><span class="secno">5. </span><span class="content">Possible Solutions</span><a class="self-link" href="#solutions"></a></h2>
   <h3 class="heading settled" data-level="5.1" id="no-action"><span class="secno">5.1. </span><span class="content">Do nothing</span><a class="self-link" href="#no-action"></a></h3>
   <p>We could simply wait for parallel versions of Range-based algorithms to make their way into the standard.  Until then, users who want to use certain view iterators as inputs to parallel algorithms are out of luck.</p>
   <p>This solution might be worth considering if parallel Range-based algorithms were on track for C++23.  But <a data-link-type="biblio" href="#biblio-p2214">[P2214]</a> "A Plan for C++23 Ranges" puts parallel Range-based algorithms in Tier 2 of Ranges work, with the caveat that the work needs to be coordinated with Executors to make sure the interface is correct.  That pushes the work well past C++23.</p>
   <p>Even if parallel Range-based algorithms were already in the draft IS, it would still be worth investigating how to get Ranges iterators to work better with non-Ranges algorithms, in the interest of having the various parts of the Standard work well together.</p>
   <h3 class="heading settled" data-level="5.2" id="change-existing"><span class="secno">5.2. </span><span class="content">Relax the <i>Cpp17</i> iterator requirements</span><a class="self-link" href="#change-existing"></a></h3>
   <p>We could change the definition of <em>Cpp17ForwardIterator</em> (<a href="http://eel.is/c++draft/forward.iterators">[forward.iterators]</a>), removing the requirement that <code class="highlight"><c- n>reference</c-></code> be defined for constant iterators. <code class="highlight"><c- n>reference</c-></code> would still need to be defined, and be <code class="highlight"><c- n>T</c-><c- o>&amp;</c-></code>, for mutable iterators.</p>
   <p>The authors do not consider this option to be feasible.  This change would break existing code that assumes that <code class="highlight"><c- n>iterator_traits</c-><c- o>&lt;</c-><c- n>I</c-><c- o>>::</c-><c- n>reference</c-></code> exists and is a reference type if the iterator category is <code class="highlight"><c- n>forward_iterator_tag</c-></code> or greater.  There are other possible solutions that don’t break existing code.</p>
   <h3 class="heading settled" data-level="5.3" id="require-concept"><span class="secno">5.3. </span><span class="content">Algorithms require concepts instead of categories</span><a class="self-link" href="#require-concept"></a></h3>
   <p>We could change the wording in <a href="http://eel.is/c++draft/algorithms.requirements">[algorithms.requirements]</a> to say that the template arguments of the algorithms shall model an iterator concept rather than meet a set of <em>Cpp17</em> requirements when the iterator is used as a constant iterator.  For example:</p>
   <blockquote>
     If an algorithm’s template parameter is named <code class="highlight"><c- n>ForwardIterator</c-></code>, <code class="highlight"><c- n>ForwardIterator1</c-></code>, or <code class="highlight"><c- n>ForwardIterator2</c-></code>, the template argument shall meet the <em>Cpp17ForwardIterator</em> requirements ([forward.iterators]) 
    <ins>if it is required to be a mutable iterator, or model <code class="highlight"><c- n>forward_iterator</c-></code> ([iterator.concept.forward]) otherwise</ins>
    . 
   </blockquote>
   <p>This change relaxes the requirements on some of the template arguments for non-Ranges algorithms.  Implementations may need to change to no longer depend on requirements that are no longer required.  It is not expected that this will be a big burden, since a well-written algorithm shouldn’t be depending on <code class="highlight"><c- n>iterator_traits</c-><c- o>&lt;</c-><c- n>I</c-><c- o>>::</c-><c- n>reference</c-></code> being a reference type for an iterator that is only used for input.</p>
   <p>This change will not break any existing code because the iterator concept imposes fewer requirements on the type than the corresponding <em>Cpp17...Iterator</em> requirements.  Any well-formed program will continue to be well-formed and have the same behavior.  Some programs that were not well-formed may become well-formed, such as the two motivating examples in this paper; these will have reasonable, non-surprising behavior.</p>
   <p>This is the solution proposed by this paper.  See immediately below for more details and analysis of this solution.</p>
   <p>Making this change only for constant iterators, not mutable iterators, is important.  See <a href="#mutable">§ 7 Mutable Iterators and Proxy Iterators</a> for details.</p>
   <p>For reasons explained below, this change is proposed only for forward, bidirectional, and random access iterators.  The requirements for input and output iterators remain unchanged.</p>
   <h2 class="heading settled" data-level="6" id="impact"><span class="secno">6. </span><span class="content">Impact and Details</span><a class="self-link" href="#impact"></a></h2>
   <h3 class="heading settled" data-level="6.1" id="changes"><span class="secno">6.1. </span><span class="content">Changes</span><a class="self-link" href="#changes"></a></h3>
   <p>In the bullets of [algorithms.requirements]/p4 for forward, bidirectional, and random access iterators leave the requirements unchanged for mutable iterators and change the requirements on constant iterators from meeting a set of <em>Cpp17...Iterator</em> requirements to modeling the corresponding iterator concept.</p>
   <h3 class="heading settled" data-level="6.2" id="relaxed"><span class="secno">6.2. </span><span class="content">Relaxed requirements</span><a class="self-link" href="#relaxed"></a></h3>
   <p>The <em>Cpp17...Iterator</em> requirements and the iterator concepts are worded very differently, making it challenging to compare them directly.</p>
   <p>The only thing that I can find that the iterator concepts require that the <em>Cpp17...Iterator</em> requirements do not is that iterator destructors must be declared <code class="highlight"><c- k>noexcept</c-></code>.  (<em>Cpp17Iterator</em> requires <em>Cpp17Destructible</em>, and <em>Cpp17Destructible</em> requires that the destructor not throw any exceptions.  But <em>Cpp17Destructible</em> allows the destructor to be declared <code class="highlight"><c- k>noexcept</c-><c- p>(</c->false<c- p>)</c-></code>, while the <code class="highlight"><c- n>input_or_output_iterator</c-></code> concept requires that the destructor be declared <code class="highlight"><c- k>noexcept</c-><c- p>(</c->true<c- p>)</c-></code>.)  Since destructors are implicitly declared <code class="highlight"><c- k>noexcept</c-></code>, and no standard iterator has a <code class="highlight"><c- k>noexcept</c-><c- p>(</c->false<c- p>)</c-></code> destructor, this difference is not meaningful and is not expected to cause any problems.</p>
   <p>The one thing that <em>Cpp17ForwardIterator</em> requires that the <code class="highlight"><c- n>forward_iterator</c-></code> concept does not is that <code class="highlight"><c- n>iterator_traits</c-><c- o>&lt;</c-><c- n>I</c-><c- o>>::</c-><c- n>reference</c-></code> be a reference type, either <code class="highlight"><c- n>T</c-><c- o>&amp;</c-></code> or <code class="highlight"><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-></code>. <code class="highlight"><c- n>forward_iterator</c-></code> requires that <code class="highlight"><c- n>iter_reference_t</c-><c- o>&lt;</c-><c- n>I</c-><c- o>></c-></code> exist, but doesn’t require that it be a reference type.  This same difference also applies to bidirectional iterators and random access iterators.  This difference is the root cause of the problems, and is the reason for this paper.</p>
   <h3 class="heading settled" data-level="6.3" id="elsewhere"><span class="secno">6.3. </span><span class="content">Other uses</span><a class="self-link" href="#elsewhere"></a></h3>
   <p>The <em>Cpp17...Iterator</em> requirements are used in several other places in the standard besides [algorithms.requirements].  It is proposed that in places where the requirements are on forward or above non-mutable iterator types that the program passes to standard algorithms, the wording is changed from meeting <em>Cpp17...Iterator</em> requirements to modeling an iterator concept, just like is being done for [algorithms.requirements].  See <a href="#wording">§ 11 Wording</a> for the five places where this happens.  Sections where the only requirements on program-supplied iterators are <em>Cpp17InputIterator</em> or <em>Cpp17OutputIterator</em> are not changed.  These are [rand.dist.samp.discrete], [rand.dist.samp.pconst], [rand.dist.samp.plinear], and [re.results.form].  Sections where the requirements on forward or above iterators are unchanged because they are required to be mutable are [rand.util.seedseq], [alg.shift], [alg.partitions].</p>
   <p>Other uses of <em>Cpp17...Iterator</em> requirements are not changed by this proposal.  In some of those cases the requirement is on a standard iterator, not a program iterator, so relaxing the requirements could break existing code.  The other uses are in [sequence.reqmts], [associative.reqmts.general], [move.iter.requirements], [locale.category], [fs.req], [fs.path.req], [fs.class.directory.iterator.general], [time.zone.db.list], [reverse.iter.requirements], [allocator.requirements.general], [stacktrace.basic.obs], [string.view.iterators], [container.requirements.general], [span.iterators], [iterator.operations], [alg.equal], and [valarray.range].</p>
   <h3 class="heading settled" data-level="6.4" id="impl-impact"><span class="secno">6.4. </span><span class="content">Implementation impact</span><a class="self-link" href="#impl-impact"></a></h3>
   <p>If any standard algorithm implementations rely on the return type of dereferencing a forward (or higher), non-mutable iterator being a reference type (see <a href="#relaxed">§ 6.2 Relaxed requirements</a>) or the iterator’s <code class="highlight"><c- n>value_type</c-></code> (see <a href="#mutable">§ 7 Mutable Iterators and Proxy Iterators</a>), those implementations will have to change to not rely on that.  Based on testing (see <a href="#experience">§ 9 Implementation Experience</a>), the number of changes of this sort will be small.</p>
   <p>Any implementation, such as MSVC, that checks the iterator category of forward iterators passed to algorithms will have to change the way those checks happen.  That change, while a little bit tedious, is not at all hard.</p>
   <p>If an algorithm checks the iterator category to choose the most efficient implementation, in some cases that code should be changed to check the iterator concept instead.  Testing turned up two cases of this in libstdc++ (see <a href="#experience">§ 9 Implementation Experience</a>), but testing probably won’t find all cases like this.  Visual code inspection might be necessary.</p>
   <p>I expect that the biggest impact on implementations will be expanding their test suites to cover the code patterns that will become well-formed once this proposal is adopted.</p>
   <h3 class="heading settled" data-level="6.5" id="user-impact"><span class="secno">6.5. </span><span class="content">User impact</span><a class="self-link" href="#user-impact"></a></h3>
   <p>No well-formed programs will become ill-formed (unless there are user-defined iterators with <code class="highlight"><c- k>noexcept</c-><c- p>(</c->false<c- p>)</c-></code> destructors) or have different behavior as a result of this change.  Some ill-formed programs will become well-formed with the behaviors users would expect.  This change will reduce the number of surprises by making code that users reasonably expect to be well-formed actually well-formed.  It is not expected that any users would be negatively impacted by this change.</p>
   <h2 class="heading settled" data-level="7" id="mutable"><span class="secno">7. </span><span class="content">Mutable Iterators and Proxy Iterators</span><a class="self-link" href="#mutable"></a></h2>
   <p>The change from <em>Cpp17...Iterator</em> requirements to iterator concepts is only being done for constant iterators.  If the requirements for mutable iterators were changed in the same way, that would allow the passing of proxy iterators to algorithms that wouldn’t handle them correctly.</p>
   <p>C++ has always had at least one standard proxy iterator: <code class="highlight"><c- n>vector</c-><c- o>&lt;</c-><c- b>bool</c-><c- o>>::</c-><c- n>iterator</c-></code>.  C++23 will get several additional proxy iterators when <a data-link-type="biblio" href="#biblio-p2321">[P2321]</a> adds <code class="highlight"><c- n>zip</c-></code> and related views to the standard library.  Proxy iterators often satisfy the requirements of mutable iterators, because they have been designed so that <code class="highlight"><c- o>*</c-><c- n>it</c-> <c- o>=</c-> <c- n>v</c-><c- p>;</c-></code> does what users expect.  But things may go wrong, either compilation errors or unexpected runtime behavior, when other mutating operations are done on proxy iterators, such as <code class="highlight"><c- n>v</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- o>*</c-><c- n>it</c-><c- p>);</c-></code> or <code class="highlight"><c- n>swap</c-><c- p>(</c-><c- o>*</c-><c- n>it1</c-><c- p>,</c-> <c- o>*</c-><c- n>it2</c-><c- p>);</c-></code>.  For mutable non-proxy iterators, <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- o>*</c-><c- n>it</c-><c- p>)</c-></code> is usually <code class="highlight"><c- n>T</c-><c- o>&amp;</c-></code>, but for mutable proxy iterators, <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- o>*</c-><c- n>it</c-><c- p>)</c-></code> is something different.  (For <code class="highlight"><c- n>zip_view</c-><c- o>::</c-><c- n>iterator</c-></code>, I believe <code class="highlight"><c- k>decltype</c-><c- p>(</c-><c- o>*</c-><c- n>it</c-><c- p>)</c-></code> is a <code class="highlight"><c- n>pair</c-></code> or <code class="highlight"><c- n>tuple</c-></code> of reference types, not a reference to a <code class="highlight"><c- n>pair</c-></code> or <code class="highlight"><c- n>tuple</c-></code>.)</p>
   <p>Ranges algorithms are designed to correctly handle proxy iterators.  For example, their specifications say that they call <code class="highlight"><c- n>iter_move</c-></code> or <code class="highlight"><c- n>iter_swap</c-></code>, which proxy iterator types can customize, when elements need to be moved or swapped.  Non-Ranges algorithms are usually not prepared to handle proxy iterators, with their specifications calling <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>move</c-></code> or <code class="highlight"><c- n>swap</c-></code> directly on the dereferenced iterators.  See the algorithms <a href="http://eel.is/c++draft/alg.move"><code class="highlight"><c- n>move</c-></code></a> and <a href="http://eel.is/c++draft/alg.swap"><code class="highlight"><c- n>swap_ranges</c-></code></a> for examples of how <code class="highlight"><c- n>std</c-><c- o>::</c-></code> algorithms and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>ranges</c-><c- o>::</c-></code> algorithms are specified differently.</p>
   <p>Proxy iterators can be used as constant iterators without problems.  It is only their use as mutable iterators in algorithms that aren’t designed for them that causes problems.</p>
   <p>Keeping the <em>Cpp17...Iterator</em> requirements for mutable iterators passed to non-Ranges algorithms prevents using proxy iterators in those situations from being well-formed, because proxy iterators do not satisfy the <em>Cpp17ForwardIterator</em> requirement that <code class="highlight"><c- n>iterator_traits</c-><c- o>&lt;</c-><c- n>I</c-><c- o>>::</c-><c- n>reference</c-></code> be <code class="highlight"><c- n>T</c-><c- o>&amp;</c-></code>.</p>
   <h2 class="heading settled" data-level="8" id="sentinels"><span class="secno">8. </span><span class="content">Sentinels</span><a class="self-link" href="#sentinels"></a></h2>
   <p>Many ranges use iterator/sentinel pairs, rather than a pair of iterators, as the bounds of the range.  Non-Ranges algorithms always require a pair of iterators that have the same type, and will not work with iterator/sentinel pairs.  If this proposal is adopted, more ranges than before will be usable with classic algorithms, but the sentinel issue will still prevent some ranges from being useful as inputs to classic algorithms.</p>
   <p>The two examples in <a href="#motivation">§ 3 Motivation</a> use iterator pairs and don’t suffer from the sentinel issue. <code class="highlight"><c- n>transform_view</c-><c- o>::</c-><c- n>end</c-><c- p>()</c-></code> returns an iterator rather than a sentinel if the base range is a common range.  In the example, the base range is <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code>, which is a common range. <code class="highlight"><c- n>iota_view</c-><c- o>::</c-><c- n>end</c-><c- p>()</c-></code> returns an iterator rather than a sentinel when the range has an upper bound of the same type as the lower bound.  It is primarily unbounded <code class="highlight"><c- n>iota_view</c-></code>s that use a sentinel.  Passing an unbounded <code class="highlight"><c- n>iota_view</c-></code> to any classic algorithm function as a first/last pair isn’t going to work well, even if first and last are of the same type.  I don’t think <code class="highlight"><c- n>iota_view</c-></code>'s use of sentinels will be a problem in practice in this area.</p>
   <p>If a range with iterator/sentinel pairs needs to be used with a classic algorithm, there is a good chance that the user can simply wrap the range in a <code class="highlight"><c- n>common_view</c-></code>, or wrap the range’s iterator and sentinel in a <code class="highlight"><c- n>common_iterator</c-></code>.  The <code class="highlight"><c- n>common_view</c-></code>'s iterators will be random access if the base range is random access and sized, and will be forward iterators if the base range’s iterator is at least forward.  That will allow the <code class="highlight"><c- n>common_view</c-></code> to be used in most places where the base range would have been usable if it had used an iterator rather than a sentinel.</p>
   <p>I am in favor of changing the non-Ranges algorithms to use iterator/sentinel pairs.  But that change can be done independently, not as part of this paper.  Both changes are useful on their own, independent of the other, and wouldn’t benefit from being tied together.</p>
   <h2 class="heading settled" data-level="9" id="experience"><span class="secno">9. </span><span class="content">Implementation Experience</span><a class="self-link" href="#experience"></a></h2>
   <p>I took a smallish test suite of the C++ parallel algorithms that I wrote a few years ago and adapted it to test this paper.  I made two copies of the test suite.  In one copy, I used <code class="highlight"><c- n>transform_view</c-></code>'s iterators, or occasionally <code class="highlight"><c- n>iota_view</c-></code>'s iterators, wherever possible.  In the other copy, I used a hand-written proxy iterator adapter wherever possible.  The proxy iterator was designed to have minimal functionality and to catch cases where code assumes that dereferencing an iterator gives you a reference type or a prvalue of the iterator’s <code class="highlight"><c- n>value_type</c-></code>.</p>
   <p>I ran this test suite with GCC 11 in C++20 mode using its libstdc++.  That turned up three places that will need to be changed if this proposal is adopted.  In two algorithms, <code class="highlight"><c- n>find_end</c-></code> and <code class="highlight"><c- n>search_n</c-></code>, the code checked the iterator category and failed to compile if the category was not at least <code class="highlight"><c- n>forward_iterator_tag</c-></code>.  With this proposal, the code will have to be changed to check the iterator concept instead of iterator category.  The other failure was in the overload of <code class="highlight"><c- n>inclusive_scan</c-></code> with no initial value.  That failed when passed a proxy iterator because it got the type of the intermediate value wrong.</p>
   <p>I also ran the test suite with Visual Studio 2022 with /std:c++latest, with the standard library cloned from the STL project on <a href="https://github.com/microsoft/STL">GitHub</a>.  I edited the parallel algorithms in the library (see <a href="#current-impl">§ 4.1 Current situation</a>), changing the requirements checks on the iterators to match this proposal, which meant changing from checking that the iterator’s category was at least <code class="highlight"><c- n>forward_iterator_tag</c-></code> to checking that the iterator satisfied the <code class="highlight"><c- n>forward_iterator</c-></code> concept.  Once I did that, all the tests passed.</p>
   <p>The parallel algorithms that were covered by my test suite are <code class="highlight"><c- n>adjacent_difference</c-></code>, <code class="highlight"><c- n>adjacent_find</c-></code>, <code class="highlight"><c- n>all_of</c-></code>, <code class="highlight"><c- n>any_of</c-></code>, <code class="highlight"><c- n>count</c-></code>, <code class="highlight"><c- n>count_if</c-></code>, <code class="highlight"><c- n>exclusive_scan</c-></code>, <code class="highlight"><c- n>find</c-></code>, <code class="highlight"><c- n>find_end</c-></code>, <code class="highlight"><c- n>find_first_of</c-></code>, <code class="highlight"><c- n>find_if</c-></code>, <code class="highlight"><c- n>find_if_not</c-></code>, <code class="highlight"><c- n>fill</c-></code>, <code class="highlight"><c- n>for_each</c-></code>, <code class="highlight"><c- n>inclusive_scan</c-></code>, <code class="highlight"><c- n>mismatch</c-></code>, <code class="highlight"><c- n>none_of</c-></code>, <code class="highlight"><c- n>reduce</c-></code>, <code class="highlight"><c- n>search</c-></code>, <code class="highlight"><c- n>search_n</c-></code>, <code class="highlight"><c- n>transform</c-></code>, <code class="highlight"><c- n>transform_exclusive_scan</c-></code>, <code class="highlight"><c- n>transform_inclusive_scan</c-></code>, and <code class="highlight"><c- n>transform_reduce</c-></code>.  This was not meant to be an exhaustive test suite.  Its purpose was to have enough coverage to get a sense for how much work it would be to implement this proposal.</p>
   <p>Based on these test results, this proposal is implementable with reasonable effort.  Some changes will have to be made to the compiler’s standard library, but those changes should not be difficult to make.  I expect that most of the effort will be spent writing tests, or adapting existing tests, to cover this area.</p>
   <h2 class="heading settled" data-level="10" id="feature-macro"><span class="secno">10. </span><span class="content">Feature Test Macro</span><a class="self-link" href="#feature-macro"></a></h2>
   <p>This change affects the well-formed-ness of certain code.  Some users might want to write their code two different ways based on whether or not a standard library has implemented this change.  Therefore, I believe that the benefit to users of a feature test macro is greater than the cost to implementers of defining it.  This proposal adds the new macro <code class="highlight"><c- n>__cpp_lib_algorithm_iterator_requirements</c-></code>.</p>
   <h2 class="heading settled" data-level="11" id="wording"><span class="secno">11. </span><span class="content">Wording</span><a class="self-link" href="#wording"></a></h2>
   <p>Changes are relative to N4888 from June 2021.</p>
   <p>Change <strong>25.2 "Algorithms requirements" [algorithms.requirements] paragraphs 4 and 5</strong> as follows, combining them into a single paragraph:</p>
   <blockquote>
     Throughout this Clause, where the template parameters are not constrained, the names of template parameters are used to express type requirements. 
    <ul>
     <li data-md>
      <ins>If an algorithm’s <em>Effects</em>: element specifies that a value pointed to by any iterator passed as an argument is modified, then the type of that argument shall meet the requirements of a mutable iterator ([iterator.requirements]).</ins>
     <li data-md>
      <p>If an algorithm’s template parameter is named <code class="highlight"><c- n>InputIterator</c-></code>, <code class="highlight"><c- n>InputIterator1</c-></code>, or <code class="highlight"><c- n>InputIterator2</c-></code>, the template argument shall meet the <em>Cpp17InputIterator</em> requirements ([input.iterators]).</p>
     <li data-md>
      <p>If an algorithm’s template parameter is named <code class="highlight"><c- n>OutputIterator</c-></code>, <code class="highlight"><c- n>OutputIterator1</c-></code>, or <code class="highlight"><c- n>OutputIterator2</c-></code>, the template argument shall meet the <em>Cpp17OutputIterator</em> requirements ([output.iterators]).</p>
     <li data-md>
      <p>
       If an algorithm’s template parameter is named <code class="highlight"><c- n>ForwardIterator</c-></code>, <code class="highlight"><c- n>ForwardIterator1</c-></code>, 
       <del>or</del>
        <code class="highlight"><c- n>ForwardIterator2</c-></code>, 
       <ins>or <code class="highlight"><c- n>NoThrowForwardIterator</c-></code>,</ins>
        the template argument shall meet the <em>Cpp17ForwardIterator</em> requirements ([forward.iterators]) 
       <ins>if it is required to be a mutable iterator, or model <code class="highlight"><c- n>forward_iterator</c-></code> ([iterator.concept.forward]) otherwise</ins>
       .
      </p>
     <li data-md>
      <p>
       If an algorithm’s template parameter is named <code class="highlight"><c- n>NoThrowForwardIterator</c-></code>, the template argument 
       <del>shall meet the <em>Cpp17ForwardIterator</em> requirements ([forward.iterators]), and</del>
        is 
       <ins>also</ins>
        required to have the property that no exceptions are thrown from increment, assignment, or comparison of, or indirection through, valid iterators.
      </p>
     <li data-md>
      <p>
       If an algorithm’s template parameter is named <code class="highlight"><c- n>BidirectionalIterator</c-></code>, <code class="highlight"><c- n>BidirectionalIterator1</c-></code>, or <code class="highlight"><c- n>BidirectionalIterator2</c-></code>, the template argument shall meet the <em>Cpp17BidirectionalIterator</em> requirements ([bidirectional.iterators]) 
       <ins>if it is required to be a mutable iterator, or model <code class="highlight"><c- n>bidirectional_iterator</c-></code> ([iterator.concept.bidir]) otherwise</ins>
       .
      </p>
     <li data-md>
      <p>
       If an algorithm’s template parameter is named <code class="highlight"><c- n>RandomAccessIterator</c-></code>, <code class="highlight"><c- n>RandomAccessIterator1</c-></code>, or <code class="highlight"><c- n>RandomAccessIterator2</c-></code>, the template argument shall meet the <em>Cpp17RandomAccessIterator</em> requirements ([random.access.iterators]) 
       <ins>if it is required to be a mutable iterator, or model <code class="highlight"><c- n>random_access_iterator</c-></code> ([iterator.concept.random.access]) otherwise</ins>
       .
      </p>
    </ul>
    <del>If an algorithm’s <em>Effects</em>: element specifies that a value pointed to by any iterator passed as an argument is modified, then that algorithm has an additional type requirement: The type of that argument shall meet the requirements of a mutable iterator ([iterator.requirements]).</del>
    <p>
     [<em>Note 1</em>: 
     <del>This requirement does</del>
     <ins>These requirements do</ins>
      not affect 
     <ins>iterator</ins>
      arguments that 
     <del>are named <code class="highlight"><c- n>OutputIterator</c-></code>, <code class="highlight"><c- n>OutputIterator1</c-></code>, or <code class="highlight"><c- n>OutputIterator2</c-></code>, because output iterators must always be mutable, nor does it affect arguments that</del>
      are constrained, for which 
     <ins>iterator category and</ins>
      mutability requirements are expressed explicitly. — <em>end note</em>]
    </p>
   </blockquote>
   <p>Change <strong>25.7.12 "Sample" [alg.random.sample] paragraphs 2 and 5</strong> as follows:</p>
   <p>Paragraph 2:</p>
   <blockquote>
    <p><em>Preconditions</em>: <code class="highlight"><c- n>out</c-></code> is not in the range <code class="highlight"><c- p>[</c-><c- n>first</c-><c- p>,</c-> <c- n>last</c-><c- p>)</c-></code>.  For the overload in namespace <code class="highlight"><c- n>std</c-></code>:</p>
    <ul>
     <li data-md>
      <p><code class="highlight"><c- n>PopulationIterator</c-></code> meets the <em>Cpp17InputIterator</em> requirements ([input.iterators]).</p>
     <li data-md>
      <p><code class="highlight"><c- n>SampleIterator</c-></code> meets the <em>Cpp17OutputIterator</em> requirements ([output.iterators]).</p>
     <li data-md>
      <p>
       <code class="highlight"><c- n>SampleIterator</c-></code> meets the <em>Cpp17RandomAccessIterator</em> requirements ([random.access.iterators]) unless <code class="highlight"><c- n>PopulationIterator</c-></code> 
       <del>meets the <em>Cpp17ForwardIterator</em> requirements ([forward.iterators])</del>
       <ins>models <code class="highlight"><c- n>forward_iterator</c-></code>([iterator.concept.forward]).</ins>
      </p>
     <li data-md>
      <p><code class="highlight"><c- n>remove_reference_t</c-><c- o>&lt;</c-><c- n>UniformRandomBitGenerator</c-><c- o>></c-></code> meets the requirements of a uniform random bit generator type ([rand.req.urng]).</p>
    </ul>
   </blockquote>
   <p>Paragraph 5:</p>
   <blockquote>
    <p><em>Remarks</em>:</p>
    <ul>
     <li data-md>
      <p>
       For the overload in namespace <code class="highlight"><c- n>std</c-></code>, stable if and only if <code class="highlight"><c- n>PopulationIterator</c-></code> 
       <del>meets the <em>Cpp17ForwardIterator</em> requirements</del>
       <ins>models <code class="highlight"><c- n>forward_iterator</c-></code></ins>
       .  For the first overload in namespace <code class="highlight"><c- n>ranges</c-></code>, stable if and only if <code class="highlight"><c- n>I</c-></code> models <code class="highlight"><c- n>forward_iterator</c-></code>.
      </p>
     <li data-md>
      <p>To the extent that the implementation of this function makes use of random numbers, the object <code class="highlight"><c- n>g</c-></code> serves as the implementation’s source of randomness.</p>
    </ul>
   </blockquote>
   <p>Change <b>25.7.9 "Unique" [alg.unique] paragraph 8.2.2</b> as follows:</p>
   <blockquote>
    <ul>
     <li data-md>
      <p>
       For the overloads with no <code class="highlight"><c- n>ExecutionPolicy</c-></code>, let <code class="highlight"><c- n>T</c-></code> be the value type of <code class="highlight"><c- n>InputIterator</c-></code>. If <code class="highlight"><c- n>InputIterator</c-></code> 
       <del>meets the <em>Cpp17ForwardIterator</em> requirements</del>
       <ins>models <code class="highlight"><c- n>forward_iterator</c-></code> ([iterator.concept.forward])</ins>
       , then there are no additional requirements for <code class="highlight"><c- n>T</c-></code>. Otherwise, if <code class="highlight"><c- n>OutputIterator</c-></code> meets the <em>Cpp17ForwardIterator</em> requirements and its value type is the same as <code class="highlight"><c- n>T</c-></code>, then <code class="highlight"><c- n>T</c-></code> meets the <em>Cpp17CopyAssignable</em> (Table 31) requirements. Otherwise, <code class="highlight"><c- n>T</c-></code> meets both the <em>Cpp17CopyConstructible</em> (Table 29) and <em>Cpp17CopyAssignable</em> requirements.
      </p>
    </ul>
   </blockquote>
   <p>Change <b>30.10.2 "<code class="highlight"><c- n>regex_match</c-></code>" [re.alg.match] paragraph 1</b> as follows:</p>
   <blockquote>
    <p>
     <em>Preconditions</em>: <code class="highlight"><c- n>BidirectionalIterator</c-></code> 
     <del>meets the <em>Cpp17BidirectionalIterator</em> requirements ([bidirectional.iterators])</del>
     <ins>models <code class="highlight"><c- n>bidirectional_iterator</c-></code> ([iterator.concept.bidir])</ins>
     .
    </p>
   </blockquote>
   <p>Change <b>30.10.3 "<code class="highlight"><c- n>regex_search</c-></code>" [re.alg.search] paragraph 1</b> as follows:</p>
   <blockquote>
    <p>
     <em>Preconditions</em>: <code class="highlight"><c- n>BidirectionalIterator</c-></code> 
     <del>meets the <em>Cpp17BidirectionalIterator</em> requirements ([bidirectional.iterators])</del>
     <ins>models <code class="highlight"><c- n>bidirectional_iterator</c-></code> ([iterator.concept.bidir])</ins>
     .
    </p>
   </blockquote>
   <p>Add the following feature test macro to <strong>[version.syn]</strong>:</p>
   <blockquote> <code class="highlight"><c- cp>#define __cpp_lib_algorithm_iterator_requirements</c-></code> <em>date</em> <em>// also in</em> <code class="highlight"><c- o>&lt;</c-><c- n>algorithm</c-><c- o>></c-></code>, <code class="highlight"><c- o>&lt;</c-><c- n>numeric</c-><c- o>></c-></code>, <code class="highlight"><c- o>&lt;</c-><c- n>memory</c-><c- o>></c-></code> </blockquote>
  </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-p2214">[P2214]
   <dd>Barry Rezvin; Conor Hoekstra; Tim Song. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2214r0.html"><cite>A Plan for C++23 Ranges</cite></a>. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2214r0.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2214r0.html</a>
   <dt id="biblio-p2321">[P2321]
   <dd>Tim Song. <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2321r2.html"><cite>zip</cite></a>. URL: <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2321r2.html">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2321r2.html</a>
  </dl>