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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/vnd.microsoft.icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">An infinite range
concept</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3555R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-01-13</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG9<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Jonathan Müller (think-cell)<br>&lt;<a href="mailto:foonathan@jonathanmueller.dev" class="email">foonathan@jonathanmueller.dev</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract</a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation</a>
<ul>
<li><a href="#statically-catch-buggy-infinite-loops" id="toc-statically-catch-buggy-infinite-loops"><span class="toc-section-number">2.1</span> Statically catch buggy infinite
loops</a></li>
<li><a href="#parallel-binary-transform" id="toc-parallel-binary-transform"><span class="toc-section-number">2.2</span> Parallel binary transform</a></li>
<li><a href="#bounds-checks-elimination" id="toc-bounds-checks-elimination"><span class="toc-section-number">2.3</span> Bounds checks elimination</a></li>
</ul></li>
<li><a href="#prior-art" id="toc-prior-art"><span class="toc-section-number">3</span> Prior art</a></li>
<li><a href="#proposed-design" id="toc-proposed-design"><span class="toc-section-number">4</span> Proposed design</a>
<ul>
<li><a href="#the-rangesinfinite_range-concept" id="toc-the-rangesinfinite_range-concept"><span class="toc-section-number">4.1</span> The
<code class="sourceCode default">ranges::infinite_range</code>
concept</a>
<ul>
<li><a href="#option-a-rangesenable_infinite_range" id="toc-option-a-rangesenable_infinite_range"><span class="toc-section-number">4.1.1</span> Option A:
<code class="sourceCode default">ranges::enable_infinite_range</code></a></li>
<li><a href="#option-b-tag-type-returned-by-.size-or-adl-size" id="toc-option-b-tag-type-returned-by-.size-or-adl-size"><span class="toc-section-number">4.1.2</span> Option B: Tag type returned by
<code class="sourceCode default">.size()</code> or ADL
<code class="sourceCode default">size()</code></a></li>
<li><a href="#option-a-vs.-option-b" id="toc-option-a-vs.-option-b"><span class="toc-section-number">4.1.3</span> Option A vs. Option B</a></li>
<li><a href="#option-c-like-option-b-but-change-rangessize" id="toc-option-c-like-option-b-but-change-rangessize"><span class="toc-section-number">4.1.4</span> Option C: Like option B, but
change <code class="sourceCode default">ranges::size</code></a></li>
</ul></li>
<li><a href="#propagating-cardinality-in-range-factories" id="toc-propagating-cardinality-in-range-factories"><span class="toc-section-number">4.2</span> Propagating cardinality in range
factories</a></li>
<li><a href="#propagating-cardinality-in-range-adaptors" id="toc-propagating-cardinality-in-range-adaptors"><span class="toc-section-number">4.3</span> Propagating cardinality in range
adaptors</a>
<ul>
<li><a href="#join_view-and-join_with_view" id="toc-join_view-and-join_with_view"><span class="toc-section-number">4.3.1</span>
<code class="sourceCode default">join_view</code> and
<code class="sourceCode default">join_with_view</code></a></li>
<li><a href="#concat_view" id="toc-concat_view"><span class="toc-section-number">4.3.2</span>
<code class="sourceCode default">concat_view</code></a></li>
<li><a href="#zip_view-and-zip_transform_view" id="toc-zip_view-and-zip_transform_view"><span class="toc-section-number">4.3.3</span>
<code class="sourceCode default">zip_view</code> and
<code class="sourceCode default">zip_transform_view</code></a></li>
</ul></li>
<li><a href="#using-rangesinfinite_range" id="toc-using-rangesinfinite_range"><span class="toc-section-number">4.4</span> Using
<code class="sourceCode default">ranges::infinite_range</code></a>
<ul>
<li><a href="#statically-catch-buggy-infinite-loops-1" id="toc-statically-catch-buggy-infinite-loops-1"><span class="toc-section-number">4.4.1</span> Statically catch buggy infinite
loops</a></li>
<li><a href="#parallel-binary-transform-1" id="toc-parallel-binary-transform-1"><span class="toc-section-number">4.4.2</span> Parallel binary
transform</a></li>
<li><a href="#bounds-check-elimination" id="toc-bounds-check-elimination"><span class="toc-section-number">4.4.3</span> Bounds check
elimination</a></li>
</ul></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">5</span> Wording</a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">6</span> References</a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>We propose a new concept
<code class="sourceCode default">ranges::infinite_range</code> to
statically detect infinite ranges. This makes it possible to statically
catch buggy infinite loops, resolving <span class="citation" data-cites="LWG4019">[<a href="#ref-LWG4019" role="doc-biblioref">LWG4019</a>]</span>, allows for a common idiom with
parallel algorithms, improving <span class="citation" data-cites="P3179R4">[<a href="#ref-P3179R4" role="doc-biblioref">P3179R4</a>]</span>, and enables optimizations to
eliminate unnecessary bounds checks, like the manual one proposed in
<span class="citation" data-cites="P3230R1">[<a href="#ref-P3230R1" role="doc-biblioref">P3230R1</a>]</span>.</p>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<h2 data-number="2.1" id="statically-catch-buggy-infinite-loops"><span class="header-section-number">2.1</span> Statically catch buggy infinite
loops<a href="#statically-catch-buggy-infinite-loops" class="self-link"></a></h2>
<p><span class="citation" data-cites="LWG4019">[<a href="#ref-LWG4019" role="doc-biblioref">LWG4019</a>]</span> points out that the following
code contains an infinite loop:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a <span class="op">=</span> views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>reverse;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>a<span class="op">.</span>begin<span class="op">()</span>; <span class="co">// infinite loop</span></span></code></pre></div>
<p>The problem is that
<code class="sourceCode default">views::iota</code> is a non-common
range. Therefore, the implementation of
<code class="sourceCode default">reverse_view::begin()</code> has to
manually find the end of
<code class="sourceCode default">views::iota</code> before going
backwards from there. But
<code class="sourceCode default">views::iota</code> is infinite, so
there is no end, and it loops forever.</p>
<p>The issue submitter proposes a detection of
<code class="sourceCode default">unreachable_sentinel_t</code> in
<code class="sourceCode default">views::reverse</code>: By definition,
ranges with that sentinel type are infinitely sized, and passing them to
<code class="sourceCode default">views::reverse</code> should not
compile. However, this solution is unsatisfactory as there are more
infinite ranges not covered by the detection of
<code class="sourceCode default">unreachable_sentinel_t</code>
(e.g. <code class="sourceCode default">views::zip(views::iota(0), views::iota(1))</code>).
We therefore need a more general mechanism to detect infinite ranges to
properly resolve <span class="citation" data-cites="LWG4019">[<a href="#ref-LWG4019" role="doc-biblioref">LWG4019</a>]</span>. This
sentiment was shared by a joint SG9/LWG meeting in St. Louis.</p>
<h2 data-number="2.2" id="parallel-binary-transform"><span class="header-section-number">2.2</span> Parallel binary transform<a href="#parallel-binary-transform" class="self-link"></a></h2>
<p>Another motivation comes from <span class="citation" data-cites="P3179R4">[<a href="#ref-P3179R4" role="doc-biblioref">P3179R4</a>]</span>, proposing rangified algorithms
with execution policies. One of them is binary transform:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>ranges<span class="op">::</span>transform<span class="op">(</span>execution<span class="op">::</span>par, rng1, rng2, output, fn<span class="op">)</span>;</span></code></pre></div>
<p>The implementation needs to know the size of the input ranges to
properly partition the input for parallel processing. The paper
originally proposed that it is enough if one of
<code class="sourceCode default">rng1</code> and
<code class="sourceCode default">rng2</code> is sized, and the algorithm
should then assume that the other one is at least as big. However, SG9
decided in Wrocław that both ranges must be sized for safety
reasons.</p>
<p>This decision was met with strong vendor resistance. A common idiom
is to pass some sort of index or constant sequence as
<code class="sourceCode default">rng1</code> and then some data as
<code class="sourceCode default">rng2</code>. The natural way, passing
the indexes as an infinite range, does not work, because infinite ranges
aren’t sized:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>ranges<span class="op">::</span>transform<span class="op">(</span>execution<span class="op">::</span>par, views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span><span class="op">)</span>, data, output, fn<span class="op">)</span>; <span class="co">// infinite range is not sized</span></span></code></pre></div>
<p>In theory, this is fine; the implementation only requires knowing
<code class="sourceCode default">min(size(rng1), size(rng2))</code>
which in the case of an infinite range is just
<code class="sourceCode default">size(rng2)</code>. But we again need a
mechanism to detect infinite ranges to implement that.</p>
<h2 data-number="2.3" id="bounds-checks-elimination"><span class="header-section-number">2.3</span> Bounds checks elimination<a href="#bounds-checks-elimination" class="self-link"></a></h2>
<p>Finally, <span class="citation" data-cites="P3230R1">[<a href="#ref-P3230R1" role="doc-biblioref">P3230R1</a>]</span> proposes
<code class="sourceCode default">views::unchecked_take</code> and
<code class="sourceCode default">views::unchecked_drop</code>. They work
just like <code class="sourceCode default">views::take</code> and
<code class="sourceCode default">views::drop</code>, but assume the
range is bigger than the number of elements taken or dropped, avoiding
bounds checks and improving performance. The common case of
<code class="sourceCode default">infinite_range | views::take(n)</code>
could be automatically optimized to <code class="sourceCode default">infinite_range | views::unchecked_take(n)</code>
— if there is a way to statically detect infinite ranges. Likewise,
bounds checks in other range adaptors could be eliminated.</p>
<p>A mechanism to detect infinite ranges can enable these
optimizations.</p>
<h1 data-number="3" id="prior-art"><span class="header-section-number">3</span> Prior art<a href="#prior-art" class="self-link"></a></h1>
<p><span class="citation" data-cites="range-v3">[<a href="#ref-range-v3" role="doc-biblioref">range-v3</a>]</span> has the concept of a <em>range
cardinality</em>. A range can have one of the following
cardinalities:</p>
<dl>
<dt>Known finite size</dt>
<dd>
the range is finite and the size is known (e.g. a
<code class="sourceCode default">vector</code>)
</dd>
<dt>Unknown finite size</dt>
<dd>
the range is finite but the size is not known (e.g. a
<code class="sourceCode default">views::filter</code> of a
<code class="sourceCode default">vector</code>)
</dd>
<dt>Infinite size</dt>
<dd>
the range is infinite
(e.g. <code class="sourceCode default">views::repeat</code>)
</dd>
<dt>Unknown</dt>
<dd>
the size of the range is completely unknown, including whether it is
finite or infinite (e.g. a
<code class="sourceCode default">generator</code>)
</dd>
</dl>
<p>This information is then propagated by (some) views. For example,
<code class="sourceCode default">transform</code> leaves the cardinality
unchanged, and a <code class="sourceCode default">filter</code> of a
finite range stays finite but a
<code class="sourceCode default">filter</code> of an infinite range has
an unknown cardinality.</p>
<p>This design was dropped during standardization due to implementation
complexity for little benefit.</p>
<h1 data-number="4" id="proposed-design"><span class="header-section-number">4</span> Proposed design<a href="#proposed-design" class="self-link"></a></h1>
<p>We propose a simplified model of cardinality. In our proposal, a
range can have only the following cardinalities:</p>
<dl>
<dt>Known finite size</dt>
<dd>
corresponding to the
<code class="sourceCode default">ranges::sized_range</code>
</dd>
<dt>Infinite size</dt>
<dd>
corresponding to the newly proposed
<code class="sourceCode default">ranges::infinite_range</code>
</dd>
<dt>Unknown</dt>
<dd>
if neither concept is satisfied
</dd>
</dl>
<p>Compared to the <span class="citation" data-cites="range-v3">[<a href="#ref-range-v3" role="doc-biblioref">range-v3</a>]</span> model, a
range can no longer have an unknown but finite size. This means that
<code class="sourceCode default">not ranges::infinite_range</code> does
not mean “finite range” it means “finite range or infinite range that we
couldn’t detect”. For example,
<code class="sourceCode default">views::filter</code> can be finite
(when filtering a finite range) or infinite (when filtering an infinite
range and keeping an infinite subset of elements). However, when it is
finite, we do not know what size it is, so it cannot model
<code class="sourceCode default">ranges::sized_range</code>.</p>
<p>The benefit of our proposal is reduced implementation complexity;
fewer views need to propagate cardinality information than in the
range-v3 model. We also believe that knowing that a range is definitely
finite is not particularly useful. The inverse, knowing that a range is
definitely infinite, is enough to catch infinite loops and omit bounds
checks.</p>
<h2 data-number="4.1" id="the-rangesinfinite_range-concept"><span class="header-section-number">4.1</span> The
<code class="sourceCode default">ranges::infinite_range</code> concept<a href="#the-rangesinfinite_range-concept" class="self-link"></a></h2>
<p>Whether a range is infinite is a semantic, not a syntactic
distinction, which requires manual opt-in or opt-out. There is one
exception: if the sentinel type of a range is
<code class="sourceCode default">unreachable_sentinel_t</code>, then the
range is definitely infinite.</p>
<p>For other ranges, we propose an opt-in: a range does not model
<code class="sourceCode default">ranges::infinite_range</code> by
default. There are two obvious ways to design the opt-in.</p>
<h3 data-number="4.1.1" id="option-a-rangesenable_infinite_range"><span class="header-section-number">4.1.1</span> Option A:
<code class="sourceCode default">ranges::enable_infinite_range</code><a href="#option-a-rangesenable_infinite_range" class="self-link"></a></h3>
<p>Similar to
<code class="sourceCode default">ranges::enable_borrowed_range</code>,
there could be a variable template
<code class="sourceCode default">ranges::enable_infinite_range</code>
that can be specialized to indicate that a type models
<code class="sourceCode default">ranges::infinite_range</code>. The
primary specialization checks whether the sentinel is
<code class="sourceCode default">unreachable_sentinel_t</code>; the
concept delegates:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>ranges <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> enable_infinite_range <span class="op">=</span> same_as<span class="op">&lt;</span>sentinel_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, unreachable_sentinel_t<span class="op">&gt;</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> infinite_range <span class="op">=</span> range<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> enable_infinite_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>User code can then opt-in by specializing
<code class="sourceCode default">ranges::enable_infinite_range</code>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> std<span class="op">::</span>ranges<span class="op">::</span>enable_infinite_range<span class="op">&lt;</span>my_infinite_range<span class="op">&gt;</span> <span class="op">=</span> <span class="kw">true</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> std<span class="op">::</span>ranges<span class="op">::</span>enable_infinite_range<span class="op">&lt;</span>my_range_adaptor_that_does_not_affect_cardinality<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span> <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>infinite_range<span class="op">&lt;</span>R<span class="op">&gt;</span>;</span></code></pre></div>
<h3 data-number="4.1.2" id="option-b-tag-type-returned-by-.size-or-adl-size"><span class="header-section-number">4.1.2</span> Option B: Tag type returned
by <code class="sourceCode default">.size()</code> or ADL
<code class="sourceCode default">size()</code><a href="#option-b-tag-type-returned-by-.size-or-adl-size" class="self-link"></a></h3>
<p>Alternatively, we could leverage the fact that a range is either
infinite or sized but never both, and have
<code class="sourceCode default">size()</code> return a tag type to
indicate infinite. Note that it is a designated tag <em>type</em> not a
special tag <em>value</em> like
<code class="sourceCode default">std::size_t(-1)</code> as we need to
distinguish it at compile-time. Let’s call it
<code class="sourceCode default">infinite_tag_t</code> for now (there is
an argument to be made for re-using
<code class="sourceCode default">unreachable_sentinel_t</code>):</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span> <span class="co">// or std::ranges</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> infinite_tag_t <span class="op">{}</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> infinite_tag_t infinite_tag;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><code class="sourceCode default">ranges::infinite_range</code> is
then modeled if and only if
<code class="sourceCode default">size()</code> returns that tag type.
Like <code class="sourceCode default">ranges::size</code> we check for
member and non-member <code class="sourceCode default">size()</code>;
unlike <code class="sourceCode default">ranges::size</code> we don’t
need to worry about arrays (definitely finite), random access ranges
with sized sentinel (definitely finite), or
<code class="sourceCode default">disable_sized_range</code> (if you
return an <code class="sourceCode default">infinite_tag_t</code> you
better use the semantics we want!).</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>ranges <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> infinite_range <span class="op">=</span> range<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">(</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>        same_as<span class="op">&lt;</span>seninel_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, unreachable_sentinel_t<span class="op">&gt;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">||</span> <span class="kw">requires</span><span class="op">(</span>R<span class="op">&amp;&amp;</span> r<span class="op">)</span> <span class="op">{</span> <span class="op">{</span> r<span class="op">.</span>size<span class="op">()</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>infinite_tag_t<span class="op">&gt;</span>; <span class="op">}</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">||</span> <span class="kw">requires</span><span class="op">(</span>R<span class="op">&amp;&amp;</span> r<span class="op">)</span> <span class="op">{</span> <span class="op">{</span> <span class="co">/*ADL*/</span>size<span class="op">(</span>r<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>infinite_tag_t<span class="op">&gt;</span>; <span class="op">}</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Note that a type that models
<code class="sourceCode default">ranges::infinite_range</code> can never
model <code class="sourceCode default">ranges::sized_range</code>, which
requires that <code class="sourceCode default">size()</code> returns an
integer type. Also note that in this option we do not propose changing
<code class="sourceCode default">std::ranges::size</code>; it will never
return <code class="sourceCode default">infinite_tag_t</code>.</p>
<p>Users can then opt-in by returning
<code class="sourceCode default">std::infinite_tag</code> from
<code class="sourceCode default">size()</code>:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> my_infinite_range <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>infinite_tag; <span class="op">}</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> my_range_adaptor_that_does_not_affect_cardinality <span class="op">{</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>    R _r;</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> std<span class="op">::</span>ranges<span class="op">::</span>sized_range<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>ranges<span class="op">::</span>size<span class="op">(</span>_r<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> std<span class="op">::</span>ranges<span class="op">::</span>infinite_range<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>infinite_tag; <span class="op">}</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h3 data-number="4.1.3" id="option-a-vs.-option-b"><span class="header-section-number">4.1.3</span> Option A vs. Option B<a href="#option-a-vs.-option-b" class="self-link"></a></h3>
<p>The example code for <code class="sourceCode default">my_range_adaptor_that_does_not_affect_cardinality</code>
shows one potential advantage of option B over option A: In many cases,
a range adaptor wants to both propagate the size (if there is one) and
the infinite-ness; see below for a list of those range adaptors. With
option B and some helper code, it is possible to do this without a lot
of code duplication.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> detail <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> potentially_infinite_size<span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>sized_range <span class="kw">auto</span><span class="op">&amp;&amp;</span> r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>ranges<span class="op">::</span>size<span class="op">(</span>r<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> potentially_infinite_size<span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>infinite_range <span class="kw">auto</span><span class="op">&amp;&amp;)</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>infinite_tag; <span class="op">}</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> enable_size <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span>R<span class="op">&amp;&amp;</span> r<span class="op">)</span> <span class="op">{</span> detail<span class="op">::</span>potentially_infinite_size<span class="op">(</span>r<span class="op">)</span>; <span class="op">}</span>;</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Changing a range adaptor from propagating only size to propagating
size and infinite-ness is then trivial:</p>
<div>
<div class="sourceCode" id="cb10"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>template &lt;class R&gt;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>class my_range_adaptor_that_does_not_affect_cardinality {</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    R _r;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>public:</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="st">-    auto size() const requires std::ranges::sized_range&lt;R&gt; { return std::ranges::size(_r); }</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="va">+    auto size() const requires detail::enable_size&lt;R&gt; { return detail::potentially_infinite_size(_r); }</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
</div>
<p>With option A, we would need to additionally write a separate
specialization for
<code class="sourceCode default">enable_infinite_range</code>.</p>
<p>The need for a
<code class="sourceCode default">potentially_infinite_size()</code>
function then makes one wonder: what if
<code class="sourceCode default">ranges::size</code> could also return
that?</p>
<h3 data-number="4.1.4" id="option-c-like-option-b-but-change-rangessize"><span class="header-section-number">4.1.4</span> Option C: Like option B, but
change <code class="sourceCode default">ranges::size</code><a href="#option-c-like-option-b-but-change-rangessize" class="self-link"></a></h3>
<p>Under this option, we still have the
<code class="sourceCode default">infinite_tag_t</code>, but we relax
<code class="sourceCode default">std::ranges::size</code>: When it
delegates to <code class="sourceCode default">.size()</code> or
ADL-<code class="sourceCode default">size()</code>, it also allows
<code class="sourceCode default">infinite_tag_t</code>. We also add a
case to return <code class="sourceCode default">infinite_tag</code>:</p>
<p>[range.prim.size]</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Given a subexpression <code class="sourceCode default">E</code> with
type <code class="sourceCode default">T</code>, let
<code class="sourceCode default">t</code> be an lvalue that denotes the
reified object for <code class="sourceCode default">E</code>. Then:</p>
<ul>
<li><p>If <code class="sourceCode default">T</code> is an array of
unknown bound ([dcl.array]),
<code class="sourceCode default">ranges​::​size(E)</code> is
ill-formed.</p></li>
<li><p>Otherwise, if <code class="sourceCode default">T</code> is an
array type, <code class="sourceCode default">ranges​::​size(E)</code> is
expression-equivalent to
<code class="sourceCode default">auto(extent_v&lt;T&gt;)</code>.</p></li>
<li><p>Otherwise, if <code class="sourceCode default">disable_sized_range&lt;remove_cv_t&lt;T&gt;&gt;</code>
([range.sized]) is <code class="sourceCode default">false</code> and
<code class="sourceCode default">auto(t.size())</code> is a valid
expression of integer-like type ([iterator.concept.winc]) <span class="add" style="color: #006e28"><ins>or of type
infinite_tag_t</ins></span>,
<code class="sourceCode default">ranges​::​size(E)</code> is
expression-equivalent to
<code class="sourceCode default">auto(​t.size())</code>.</p></li>
<li><p>Otherwise, if <code class="sourceCode default">T</code> is a
class or enumeration type, <code class="sourceCode default">disable_sized_range&lt;remove_cv_t&lt;T&gt;&gt;</code>
is <code class="sourceCode default">false</code> and
<code class="sourceCode default">auto(size(t))</code> is a valid
expression of integer-like type <span class="add" style="color: #006e28"><ins>or of type infinite_tag_t</ins></span> where
the meaning of size is established as-if by performing
argument-dependent lookup only ([basic.lookup.argdep]), then
<code class="sourceCode default">ranges​::​size(E)</code> is
expression-equivalent to that expression.</p></li>
<li><p>Otherwise, if <code class="sourceCode default">to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t))</code>
([ranges.syn]) is a valid expression and the types
<code class="sourceCode default">I</code> and
<code class="sourceCode default">S</code> of
<code class="sourceCode default">ranges​::​begin(t)</code> and
<code class="sourceCode default">ranges​::​end(t)</code> (respectively)
model both
<code class="sourceCode default">sized_sentinel_for&lt;S, I&gt;</code>
([iterator.concept.sizedsentinel]) and
<code class="sourceCode default">forward_iterator&lt;I&gt;</code>, then
<code class="sourceCode default">ranges​::​size(E)</code> is
expression-equivalent to <code class="sourceCode default">to-unsigned-like(ranges​::​end(t) - ranges​::​begin(t))</code>.</p></li>
<li><p><span class="add" style="color: #006e28"><ins>Otherwise, if
<span><code class="sourceCode default">same_as&lt;sentinel_t&lt;T&gt;, unreachable_sentinel_t&gt;</code></span>
is <span><code class="sourceCode default">true</code></span>,
<span><code class="sourceCode default">ranges​::​size(E)</code></span> is
expression-equivalent to
<span><code class="sourceCode default">infinite_tag</code></span>.</ins></span></p></li>
<li><p>Otherwise,
<code class="sourceCode default">ranges​::​size(E)</code> is
ill-formed.</p></li>
</ul>
</blockquote>
<p><code class="sourceCode default">ranges::sized_range</code> then
additionally checks for a finite size:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> sized_range <span class="op">=</span> range<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="kw">requires</span><span class="op">(</span>T<span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span> <span class="kw">requires</span> is<span class="op">-</span>integer<span class="op">-</span>like<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>size<span class="op">(</span>t<span class="op">))&gt;</span>; <span class="op">}</span>;</span></code></pre></div>
<p>For <code class="sourceCode default">infinite_range</code>,
<code class="sourceCode default">ranges::size</code> has to return
<code class="sourceCode default">infinite_tag_t</code>:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> infinite_range <span class="op">=</span> range<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="kw">requires</span><span class="op">(</span>T<span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span> <span class="op">{</span> ranges<span class="op">::</span>size<span class="op">(</span>t<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>infinite_tag_t<span class="op">&gt;</span>; <span class="op">}</span>;</span></code></pre></div>
<p>This simplifies the conditional opt-in:</p>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>template &lt;class R&gt;</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>class my_range_adaptor_that_does_not_affect_cardinality {</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    R _r;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>public:</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="st">-    auto size() const requires std::ranges::sized_range&lt;R&gt; { return std::ranges::size(_r); }</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="va">+    auto size() const requires requires(R&amp;&amp; r) { std::ranges::size(r); } { return std::ranges::size(_r); }</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>};</span></code></pre></div>
</div>
<p>Option C is not a breaking change: We only changed cases where
<code class="sourceCode default">ranges::size</code> would have been
ill-formed before. However, we break assumptions about an equivalence
between <code class="sourceCode default">ranges::sized_range</code> and
<code class="sourceCode default">ranges::size</code>. Badly constrained
generic code might have called
<code class="sourceCode default">ranges::size</code> unconditionally.
But again, this just means trading one error message
(<code class="sourceCode default">ranges::size</code> does not exist) to
anther one (<code class="sourceCode default">infinite_tag_t</code> is
not an integer).</p>
<p>However, re-using
<code class="sourceCode default">ranges::size</code> like that might be
confusing.</p>
<h2 data-number="4.2" id="propagating-cardinality-in-range-factories"><span class="header-section-number">4.2</span> Propagating cardinality in
range factories<a href="#propagating-cardinality-in-range-factories" class="self-link"></a></h2>
<p><code class="sourceCode default">empty_view</code> and
<code class="sourceCode default">single_view</code> are definitely
finite, so don’t need to change. Unbounded
<code class="sourceCode default">iota_view</code> and
<code class="sourceCode default">repeat_view</code> are already covered
as they use
<code class="sourceCode default">unreachable_sentinel_t</code>.
<code class="sourceCode default">istream_view</code> and
<code class="sourceCode default">generator</code> have an unknown
cardinality, so they can never model
<code class="sourceCode default">ranges::infinite_range</code>. We
therefore do not propose any changes here.</p>
<p><code class="sourceCode default">subrange</code> is interesting: If
the sentinel type is
<code class="sourceCode default">unreachable_sentinel_t</code>, it will
model <code class="sourceCode default">ranges::infinite_range</code>
automatically. Otherwise, the cardinality is unknown and cannot be
easily derived as we lost information about the range type the iterators
came from. We could extend the
<code class="sourceCode default">ranges::subrange_kind</code>
enumeration to add an additional
<code class="sourceCode default">subrange_kind::infinite</code> value.
Similar to<code class="sourceCode default">subrange_kind::unsized</code>
subrange it would not store a size value, but it would unconditionally
model <code class="sourceCode default">ranges::infinite_range</code>. As
a result, constructing a
<code class="sourceCode default">subrange_kind::infinite</code> subrange
has a precondition that the range is actually infinite. Moreover, this
precondition is safety critical as an implementation might choose to
elide bounds checks for infinite range access. We therefore do not
propose any changes to <code class="sourceCode default">subrange</code>
in this paper; that option can always be explored later.</p>
<h2 data-number="4.3" id="propagating-cardinality-in-range-adaptors"><span class="header-section-number">4.3</span> Propagating cardinality in
range adaptors<a href="#propagating-cardinality-in-range-adaptors" class="self-link"></a></h2>
<blockquote>
<p>Note: This is meant to be an exhaustive list. If a range adaptor is
not mentioned here, we have forgotten about it.</p>
</blockquote>
<p>The following range adaptors model
<code class="sourceCode default">ranges::infinite_range</code> if and
only if their underlying range models
<code class="sourceCode default">ranges::infinite_range</code>:</p>
<ul>
<li><code class="sourceCode default">ref_view</code></li>
<li><code class="sourceCode default">owning_view</code></li>
<li><code class="sourceCode default">as_rvalue_view</code></li>
<li><code class="sourceCode default">transform_view</code></li>
<li><code class="sourceCode default">drop_view</code></li>
<li><code class="sourceCode default">lazy_split_view</code></li>
<li><code class="sourceCode default">split_view</code></li>
<li><code class="sourceCode default">common_view</code></li>
<li><code class="sourceCode default">reverse_view</code></li>
<li><code class="sourceCode default">as_const_view</code></li>
<li><code class="sourceCode default">elements_view</code></li>
<li><code class="sourceCode default">enumerate_view</code></li>
<li><code class="sourceCode default">adjacent_view</code></li>
<li><code class="sourceCode default">adjacent_transform_view</code></li>
<li><code class="sourceCode default">chunk_view</code></li>
<li><code class="sourceCode default">slide_view</code></li>
<li><code class="sourceCode default">chunk_by_view</code></li>
<li><code class="sourceCode default">stride_view</code></li>
<li><code class="sourceCode default">cache_latest_view</code></li>
</ul>
<p>We propose that they get the appropriate opt-in.</p>
<p>The following range adaptors are definitely finite or have an unknown
cardinality:</p>
<ul>
<li><code class="sourceCode default">filter_view</code> (unknown
cardinality)</li>
<li><code class="sourceCode default">take_view</code> (finite)</li>
<li><code class="sourceCode default">take_while_view</code> (unknown
cardinality)</li>
<li><code class="sourceCode default">drop_while_view</code> (unknown
cardinality)</li>
</ul>
<p>We thus do not propose any changes for them.</p>
<p>The remaining range adaptors require more detailed discussion.</p>
<h3 data-number="4.3.1" id="join_view-and-join_with_view"><span class="header-section-number">4.3.1</span>
<code class="sourceCode default">join_view</code> and
<code class="sourceCode default">join_with_view</code><a href="#join_view-and-join_with_view" class="self-link"></a></h3>
<p>We propose that <code class="sourceCode default">join_view</code>
models <code class="sourceCode default">ranges::infinite_range</code> if
and only if the underlying outer range models
<code class="sourceCode default">ranges::infinite_range</code> (joining
infinitely many things together is definitely infinite). Note that the
cardinality is unknown if only the underlying inner range models
<code class="sourceCode default">ranges::infinite_range</code>: The
outer range could be empty in which case
<code class="sourceCode default">join_view</code> is empty.</p>
<p>If we have a mechanism to statically determine whether a range is
non-empty, we could have
<code class="sourceCode default">join_view</code> model
<code class="sourceCode default">ranges::infinite_range</code> in more
cases. However, we do not propose such a mechanism at this time.</p>
<p>The same logic applies to
<code class="sourceCode default">join_with_view</code>. Note that there
it is also not enough to only know that the separator models
<code class="sourceCode default">ranges::infinite_range</code> for the
same reason.</p>
<h3 data-number="4.3.2" id="concat_view"><span class="header-section-number">4.3.2</span>
<code class="sourceCode default">concat_view</code><a href="#concat_view" class="self-link"></a></h3>
<p>We propose that <code class="sourceCode default">concat_view</code>
models <code class="sourceCode default">ranges::infinite_range</code> if
at least one of the underlying ranges models
<code class="sourceCode default">ranges::infinite_range</code>.</p>
<h3 data-number="4.3.3" id="zip_view-and-zip_transform_view"><span class="header-section-number">4.3.3</span>
<code class="sourceCode default">zip_view</code> and
<code class="sourceCode default">zip_transform_view</code><a href="#zip_view-and-zip_transform_view" class="self-link"></a></h3>
<p>We propose that <code class="sourceCode default">zip_view</code> and
<code class="sourceCode default">zip_transform_view</code> model
<code class="sourceCode default">ranges::infinite_range</code> if all of
the underlying ranges model
<code class="sourceCode default">ranges::infinite_range</code>.</p>
<h2 data-number="4.4" id="using-rangesinfinite_range"><span class="header-section-number">4.4</span> Using
<code class="sourceCode default">ranges::infinite_range</code><a href="#using-rangesinfinite_range" class="self-link"></a></h2>
<h3 data-number="4.4.1" id="statically-catch-buggy-infinite-loops-1"><span class="header-section-number">4.4.1</span> Statically catch buggy
infinite loops<a href="#statically-catch-buggy-infinite-loops-1" class="self-link"></a></h3>
<p>Once <code class="sourceCode default">ranges::infinite_range</code>
exist, we can statically catch buggy infinite loops. Technically, an
implementation is allowed to do that as a matter of QoI due to the
guarantees in [intro.progress]: If an algorithm or view has an infinite
loop without side-effects, the behavior is undefined, and undefined
behavior can be lifted into compile-time errors.</p>
<p>However, given that an issue was already filed for
<code class="sourceCode default">views::reverse</code>, we should
mandate a detection at least for that view adaptor. We therefore propose
that <code class="sourceCode default">views::reverse</code> is
ill-formed for ranges modeling
<code class="sourceCode default">ranges::infinite_range</code> but not
also <code class="sourceCode default">ranges::common_range</code>,
resolving <span class="citation" data-cites="LWG4019">[<a href="#ref-LWG4019" role="doc-biblioref">LWG4019</a>]</span>.</p>
<p>Preventing infinite ranges in other situations requires
implementation experience and has to be done more careful. For example,
passing an infinite range to
<code class="sourceCode default">std::ranges::for_each</code> is fine if
the predicate has side effects, but calling
<code class="sourceCode default">std::ranges::sort</code> on it is an
error (unless the user does something funky with the comparison or
swap). We therefore do not propose additional infinite loop
detection.</p>
<h3 data-number="4.4.2" id="parallel-binary-transform-1"><span class="header-section-number">4.4.2</span> Parallel binary transform<a href="#parallel-binary-transform-1" class="self-link"></a></h3>
<p>As <span class="citation" data-cites="P3179R4">[<a href="#ref-P3179R4" role="doc-biblioref">P3179R4</a>]</span> is still
in-flight, we do not propose any changes to it in this paper. We expect
harmonization to appear in a follow-up paper.</p>
<h3 data-number="4.4.3" id="bounds-check-elimination"><span class="header-section-number">4.4.3</span> Bounds check elimination<a href="#bounds-check-elimination" class="self-link"></a></h3>
<p>Optimizations to eliminate bounds checks for infinite ranges are QoI
and do not need to be mandated. We expect vendors to implement them once
the concept is available.</p>
<h1 data-number="5" id="wording"><span class="header-section-number">5</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>TBD</p>
<h1 data-number="6" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list">
<div id="ref-LWG4019" class="csl-entry" role="listitem">
[LWG4019] Barry Revzin. Reversing an infinite range leads to an infinite
loop. <a href="https://wg21.link/lwg4019"><div class="csl-block">https://wg21.link/lwg4019</div></a>
</div>
<div id="ref-P3179R4" class="csl-entry" role="listitem">
[P3179R4] Ruslan Arutyunyan, Alexey Kukanov, Bryce Adelstein Lelbach.
2024-12-11. C++ parallel range algorithms. <a href="https://wg21.link/p3179r4"><div class="csl-block">https://wg21.link/p3179r4</div></a>
</div>
<div id="ref-P3230R1" class="csl-entry" role="listitem">
[P3230R1] Hewill Kang. 2024-12-01. views::unchecked_(take|drop). <a href="https://wg21.link/p3230r1"><div class="csl-block">https://wg21.link/p3230r1</div></a>
</div>
<div id="ref-range-v3" class="csl-entry" role="listitem">
[range-v3] range-v3. <a href="https://github.com/ericniebler/range-v3"><div class="csl-block">https://github.com/ericniebler/range-v3</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
