<!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="2019-11-08" />
  <title>forwarding-range&lt;T&gt; is too subtle</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%;}
  </style>
  <style>
code.sourceCode > span { display: inline-block; line-height: 1.25; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
  { counter-reset: source-line 0; }
pre.numberSource code > span
  { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
  { content: counter(source-line);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  background-color: #f6f8fa; }
@media screen {
code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span. { } /* Normal */
code span.al { color: #ff0000; } /* Alert */
code span.an { } /* Annotation */
code span.at { } /* Attribute */
code span.bn { color: #9f6807; } /* BaseN */
code span.bu { color: #9f6807; } /* BuiltIn */
code span.cf { color: #00607c; } /* ControlFlow */
code span.ch { color: #9f6807; } /* Char */
code span.cn { } /* Constant */
code span.co { color: #008000; font-style: italic; } /* Comment */
code span.cv { color: #008000; font-style: italic; } /* CommentVar */
code span.do { color: #008000; } /* Documentation */
code span.dt { color: #00607c; } /* DataType */
code span.dv { color: #9f6807; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #9f6807; } /* Float */
code span.fu { } /* Function */
code span.im { } /* Import */
code span.in { color: #008000; } /* Information */
code span.kw { color: #00607c; } /* Keyword */
code span.op { color: #af1915; } /* Operator */
code span.ot { } /* Other */
code span.pp { color: #6f4e37; } /* Preprocessor */
code span.re { } /* RegionMarker */
code span.sc { color: #9f6807; } /* SpecialChar */
code span.ss { color: #9f6807; } /* SpecialString */
code span.st { color: #9f6807; } /* String */
code span.va { } /* Variable */
code span.vs { color: #9f6807; } /* VerbatimString */
code span.wa { color: #008000; font-weight: bold; } /* Warning */
code.diff {color: #898887}
code.diff span.va {color: #006e28}
code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
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; }

div#refs p { padding-left: 32px; text-indent: -32px; }
</style>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #e6ffed;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
</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"><em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><code class="sourceCode cpp"><span class="op">&lt;</span>T<span class="op">&gt;</span></code> is too subtle</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P1870R1</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2019-11-08</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#introduction"><span class="toc-section-number">2</span> Introduction<span></span></a></li>
<li><a href="#naming"><span class="toc-section-number">3</span> Naming<span></span></a></li>
<li><a href="#opting-into-forwarding-range"><span class="toc-section-number">4</span> Opting into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><span></span></a><ul>
<li><a href="#history"><span class="toc-section-number">4.1</span> History<span></span></a></li>
<li><a href="#issues-with-overloading"><span class="toc-section-number">4.2</span> Issues with overloading<span></span></a></li>
<li><a href="#how-many-mechanisms-do-we-need"><span class="toc-section-number">4.3</span> How many mechanisms do we need?<span></span></a></li>
<li><a href="#hard-to-get-correct"><span class="toc-section-number">4.4</span> Hard to get correct<span></span></a></li>
</ul></li>
<li><a href="#proposal"><span class="toc-section-number">5</span> Proposal<span></span></a><ul>
<li><a href="#wording"><span class="toc-section-number">5.1</span> Wording<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements"><span class="toc-section-number">6</span> Acknowledgements<span></span></a></li>
<li><a href="#references"><span class="toc-section-number">7</span> References<span></span></a></li>
</ul>
</div>
<h1 id="revision-history" style="border-bottom:1px solid #cccccc"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>R0 <span class="citation" data-cites="P1870R0">[<a href="#ref-P1870R0" role="doc-biblioref">P1870R0</a>]</span> of this paper was presented to LEWG in Belfast. There was consensus to change the opt-in mechanism to use the trait rather than the non-member function as presented in the paper. However, there was unanimous dissent to remove the ability to invoke <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> (and other CPOs) on rvalues. This draft adds that ability back.</p>
<p>In short, the only change then is the opt-in mechanism. All other functionality is preserved.</p>
<p>This paper also addresses the NB comments <a href="https://github.com/cplusplus/nbballot/issues/275">US279</a> and <a href="https://github.com/cplusplus/nbballot/issues/276">GB280</a>, and is relevant to the resolution of <a href="https://github.com/cplusplus/nbballot/issues/272">US276</a> and <a href="https://github.com/cplusplus/nbballot/issues/282">US286</a>.</p>
<h1 id="introduction" style="border-bottom:1px solid #cccccc"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>One of the concepts introduces by Ranges is <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. The salient aspect of what makes a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is stated in <a href="http://eel.is/c++draft/range.range">[range.range]</a>:</p>
<blockquote>
<p>the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</p>
</blockquote>
<p>clarified more in the subsequent note:</p>
<blockquote>
<p><em>[ Note<em>: Since the validity of iterators is not tied to the lifetime of an object whose type models <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling. </em>— end note ]</em></p>
</blockquote>
<p>For example, <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is not a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> because any iterator into a <code class="sourceCode cpp">vector</code> is of course dependent on the lifetime of the <code class="sourceCode cpp">vector</code> itself. On the other hand, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code> <em>is</em> a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> because it does not actually own anything - any iterator you get out of it has its lifetime tied to some other object entirely.</p>
<p>But while <code class="sourceCode cpp">span</code> and <code class="sourceCode cpp">subrange</code> each model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, not all views do. For instance, <code class="sourceCode cpp">transform_view</code> would not because its iterators’ validity would be tied to the unary function that is the actual transform. You could increment those iterators, but you couldn’t dereference them. Likewise, <code class="sourceCode cpp">filter_view</code>’s iterator validity is going to be based on its predicate.</p>
<p>Really, a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is quite a rare creature.<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Value category also plays into this. Notably, <em>lvalue</em> ranges all model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> – the “object” in question in this case is an lvalue reference, and the validity of iterators into a range are never going to be tied to the lifetime of some reference to that range. For instance, <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is not a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, but <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span></code> is. The only question is about <em>rvalue</em> ranges. If I have a function that either takes a range by forwarding reference or by value, I have to know what I can do with it.</p>
<p>Ranges uses this in two kinds of places:</p>
<ul>
<li>Many algorithms return iterators into a range. Those algorithms conditionally return either <code class="sourceCode cpp">iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code> or <code class="sourceCode cpp">dangling</code> based on whether or not <code class="sourceCode cpp">R</code> satisfies <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> (because if <code class="sourceCode cpp">R</code> did not, then such iterators would not be valid, so they are not returned). This type is called <code class="sourceCode cpp">safe_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code> and appears over 100 times in <a href="http://eel.is/c++draft/algorithms">[algorithms]</a>.</li>
<li>Range adapters can only be used on rvalue ranges if they satisfy either <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> or they decay to a <code class="sourceCode cpp">view</code>. The former because you may need to keep iterators into them past their lifetime, and the latter because if you can cheaply copy it than that works too. This higher-level concept is called <code class="sourceCode cpp">viewable_range</code>, and every range adapter depends on it.</li>
</ul>
<p>That is, <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is a very important concept. It is used practically everywhere. It also conveys a pretty subtle and very rare feature of a type: that its iterators can outlive it. Syntactically, there is no difference between a <code class="sourceCode cpp">range</code>, a <code class="sourceCode cpp">view</code>, and a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, so the question is - how does a type declare itself to have this feature?</p>
<h1 id="naming" style="border-bottom:1px solid #cccccc"><span class="header-section-number">3</span> Naming<a href="#naming" class="self-link"></a></h1>
<p>The name <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is problematic. There is a concept <code class="sourceCode cpp">std<span class="op">::</span>forward_range</code> which is completely unrelated. A fairly common first response is that it has something to do with forwarding iterators. But the name actually comes from the question of whether you can use a forwarding reference <code class="sourceCode cpp">range</code> safely.</p>
<p>However, coming up with a good name for it is very difficult. The concept has to refer to the range, but the salient aspect really has more to do with the iterators. Words that seem relevant are detachable, untethered, unfettered, nondangling. But then applying them to the range ends up being a mouthful: <code class="sourceCode cpp">range_with_detachable_iterators</code>. Granted, this concept isn’t <em>directly</em> used in too many places so maybe a long name is fine.</p>
<p>The naming direction this proposal takes is to use the name <code class="sourceCode cpp">safe_range</code>, based on the existence of <code class="sourceCode cpp">safe_iterator</code> and <code class="sourceCode cpp">safe_subrange</code>. It still doesn’t seem like a great name though, but at least all the relevant library things are similarly named.</p>
<p>Also the concept is still exposition-only, despite being a fairly important concept that people may want to use in their own code. This can be worked around:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-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="cb1-2"><a href="#cb1-2"></a><span class="kw">concept</span> my_forwarding_range <span class="op">=</span> std<span class="op">::</span>range<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>    <span class="op">&amp;&amp;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>std<span class="op">::</span>safe_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, std<span class="op">::</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>But this seems like the kind of thing the standard library should provide directly.</p>
<h1 id="opting-into-forwarding-range" style="border-bottom:1px solid #cccccc"><span class="header-section-number">4</span> Opting into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><a href="#opting-into-forwarding-range" class="self-link"></a></h1>
<p>Types must opt into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, and this is done by having non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> overloads that must take the type by either value or rvalue reference. At first glance, it might seem like this is impossible to do in the language but Ranges accomplishes this through the clever<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> use of poison-pill overload:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">namespace</span> __begin <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>    <span class="co">// poison pill</span></span>
<span id="cb2-3"><a href="#cb2-3"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="dt">void</span> begin<span class="op">(</span>T<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R<span class="op">&gt;</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>    <span class="kw">concept</span> has_non_member <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>
<span id="cb2-7"><a href="#cb2-7"></a>            begin<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>R<span class="op">&gt;(</span>r<span class="op">))</span>;</span>
<span id="cb2-8"><a href="#cb2-8"></a>        <span class="op">}</span>;</span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="op">}</span></span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb2-12"><a href="#cb2-12"></a>    <span class="kw">struct</span> my_vector <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span>;</span>
<span id="cb2-13"><a href="#cb2-13"></a>    <span class="kw">auto</span> begin<span class="op">(</span>my_vector <span class="kw">const</span><span class="op">&amp;)</span>;</span>
<span id="cb2-14"><a href="#cb2-14"></a><span class="op">}</span></span></code></pre></div>
<p>Does <code class="sourceCode cpp">N<span class="op">::</span>my_vector</code> satisfy the concept <code class="sourceCode cpp">__begin<span class="op">::</span>has_non_member</code>? It does not. The reason is that the poison pill candidate binds an rvalue reference to the argument while the ADL candidate binds an lvalue reference, and tiebreaker of rvalue reference to lvalue reference happens much earlier than non-template to template. The only way to have a better match than the poison pill for rvalues is to either have a function/function template that takes its argument by value or rvalue reference, or to have a function template that takes a constrained forwarding reference.</p>
<p>This is a pretty subtle design decision - why did we decide to use the existence of non-member overloads as the opt-in?</p>
<h2 id="history"><span class="header-section-number">4.1</span> History<a href="#history" class="self-link"></a></h2>
<p>This design comes from <span class="citation" data-cites="stl2.547">[<a href="#ref-stl2.547" role="doc-biblioref">stl2.547</a>]</span>, with the expressed intent:</p>
<blockquote>
<p>Redesign begin/end CPOs to eliminate deprecated behavior and to force range types to opt in to working with rvalues, thereby giving users a way to detect that, for a particular range type, iterator validity does not depend on the range’s lifetime.</p>
</blockquote>
<p>which led to <span class="citation" data-cites="P0970R1">[<a href="#ref-P0970R1" role="doc-biblioref">P0970R1</a>]</span>, which describes the earlier problems with <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code> thusly:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> For the sake of compatibility with <code class="sourceCode cpp">std<span class="op">::</span>begin</code> and ease of migration, <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>begin</code> accepted rvalues and treated them the same as <code class="sourceCode cpp"><span class="kw">const</span></code> lvalues. This behavior was deprecated because it is fundamentally unsound: any iterator returned by such an overload is highly likely to dangle after the full-expression that contained the invocation of <code class="sourceCode cpp">begin</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> Another problem, and one that until recently seemed unrelated to the design of <code class="sourceCode cpp">begin</code>, was that algorithms that return iterators will wrap those iterators in <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>dangling<span class="op">&lt;&gt;</span></code> if the range passed to them is an rvalue. This ignores the fact that for some range types — <code class="sourceCode cpp">std<span class="op">::</span>span</code>, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>, and P0789’s <code class="sourceCode cpp">subrange</code>, in particular — the iterator’s validity does not depend on the range’s lifetime at all. In the case where an rvalue of one of the above types is passed to an algorithm, returning a wrapped iterator is totally unnecessary.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span> The author believed that to fix the problem with <code class="sourceCode cpp">subrange</code> and <code class="sourceCode cpp">dangling</code> would require the addition of a new trait to give the authors of range types a way to say whether its iterators can safely outlive the range. That felt like a hack.</p>
</blockquote>
<p>This paper was presented in Rapperswil 2018, partially jointly with <span class="citation" data-cites="P0896R1">[<a href="#ref-P0896R1" role="doc-biblioref">P0896R1</a>]</span>, and as far as I can tell from the minutes, this subtlety was not discussed.</p>
<h2 id="issues-with-overloading"><span class="header-section-number">4.2</span> Issues with overloading<a href="#issues-with-overloading" class="self-link"></a></h2>
<p>In <span class="citation" data-cites="stl2.592">[<a href="#ref-stl2.592" role="doc-biblioref">stl2.592</a>]</span>, Eric Niebler points out that the current wording has the non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> for <code class="sourceCode cpp">subrange</code> taking it by rvalue reference instead of by value, meaning that <code class="sourceCode cpp"><span class="kw">const</span> subrange</code> doesn’t count as a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. But there is a potentially broader problem, which is that overload resolution will consider the <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> functions for <code class="sourceCode cpp">subrange</code> even in contexts where they would be a worse match than the poison pill (i.e. they would involve conversions), and some of those contexts could lead to hard instantiation errors. So Eric suggests that the overload should be:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">friend</span> <span class="kw">constexpr</span> I begin<span class="op">(</span>same_as<span class="op">&lt;</span>subrange<span class="op">&gt;</span> <span class="kw">auto</span> r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> r<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span></code></pre></div>
<p>Of the types in the standard library that should model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, three of the four should take the same treatment (only <code class="sourceCode cpp">iota_view</code> doesn’t need to worry). That is, in order to really ensure correctness by avoiding any potential hard instantiation errors, we have to write non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> function templates that constrain their argument via <code class="sourceCode cpp">same_as<span class="op">&lt;</span>R<span class="op">&gt;</span></code>?</p>
<p>The issue goes on to further suggest that perhaps the currect overload is really:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">friend</span> <span class="kw">constexpr</span> I begin<span class="op">(</span><em>same-ish</em><span class="op">&lt;</span>subrange<span class="op">&gt;</span> <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> r<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span></code></pre></div>
<p>And there is an NB comment that suggests the <em><code class="sourceCode cpp">same<span class="op">-</span>ish</code></em><code class="sourceCode cpp"><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">auto</span><span class="op">&amp;&amp;</span></code> spelling for some times and <code class="sourceCode cpp">same_as<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">auto</span></code> spelling for others. What’s the distinction? To be honest, I do not understand.</p>
<p>Now we’ve started from needing a non-member <code class="sourceCode cpp">begin<span class="op">()</span></code>/<code class="sourceCode cpp">end<span class="op">()</span></code> that take an argument by value or rvalue reference – not necessarily to actually be invoked on an rvalue – but that runs into potential problems, that need to be solved by making that non-member a constrained template that either takes by value or forwarding reference, but constrained to a single type?</p>
<h2 id="how-many-mechanisms-do-we-need"><span class="header-section-number">4.3</span> How many mechanisms do we need?<a href="#how-many-mechanisms-do-we-need" class="self-link"></a></h2>
<p>At this point, we have three concepts in Ranges that have some sort of mechanism to opt-in/opt-out:</p>
<ul>
<li><em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>: provide a non-member <code class="sourceCode cpp">begin<span class="op">()</span></code>/<code class="sourceCode cpp">end<span class="op">()</span></code> that take their argument by value or rvalue reference (but really probably a constrained function template)</li>
<li><code class="sourceCode cpp">view</code>: opt-in via the <code class="sourceCode cpp">enable_view</code> type trait</li>
<li><code class="sourceCode cpp">sized_range</code>: opt-out via the <code class="sourceCode cpp">disable_sized_range</code> trait</li>
</ul>
<p>I don’t think we need different mechanisms for each trait. I know Eric and Casey viewed having to have a type trait as a hack, but it’s a hack around not having a language mechanism to express opt-in (see also <span class="citation" data-cites="P1900R0">[<a href="#ref-P1900R0" role="doc-biblioref">P1900R0</a>]</span>). It’s still the best hack we have, that’s the easiest to understand, that’s probably more compiler-efficient as well (overload resolution is expensive!)</p>
<h2 id="hard-to-get-correct"><span class="header-section-number">4.4</span> Hard to get correct<a href="#hard-to-get-correct" class="self-link"></a></h2>
<p>Now that MSVC’s standard library implementation is open source, we can take a look at how they went about implementing the opt-in for <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> in their implementation of <code class="sourceCode cpp">basic_string_view</code> <span class="citation" data-cites="msvc.basic_string_view">[<a href="#ref-msvc.basic_string_view" role="doc-biblioref">msvc.basic_string_view</a>]</span>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="pp">#ifdef __cpp_lib_concepts</span></span>
<span id="cb5-2"><a href="#cb5-2"></a>    _NODISCARD <span class="kw">friend</span> <span class="kw">constexpr</span> const_iterator begin<span class="op">(</span><span class="kw">const</span> basic_string_view<span class="op">&amp;</span> _Right<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>        <span class="co">// non-member overload that accepts rvalues to model the exposition-only forwarding-range concept</span></span>
<span id="cb5-4"><a href="#cb5-4"></a>        <span class="cf">return</span> _Right<span class="op">.</span>begin<span class="op">()</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a>    <span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6"></a>    _NODISCARD <span class="kw">friend</span> <span class="kw">constexpr</span> const_iterator end<span class="op">(</span><span class="kw">const</span> basic_string_view<span class="op">&amp;</span> _Right<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb5-7"><a href="#cb5-7"></a>        <span class="co">// Ditto modeling forwarding-range</span></span>
<span id="cb5-8"><a href="#cb5-8"></a>        <span class="cf">return</span> _Right<span class="op">.</span>end<span class="op">()</span>;</span>
<span id="cb5-9"><a href="#cb5-9"></a>    <span class="op">}</span></span>
<span id="cb5-10"><a href="#cb5-10"></a><span class="pp">#endif </span><span class="co">// __cpp_lib_concepts</span></span></code></pre></div>
<p>Note that these overloads take their arguments by reference-to-<code class="sourceCode cpp"><span class="kw">const</span></code>. But the non-member overloads need to take their arguments by either value or rvalue reference, otherwise the poison pill is a better match, as described earlier. So at this moment, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code> fails to satisfy <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. If even Casey can make this mistake, how is anybody going to get it right?</p>
<h1 id="proposal" style="border-bottom:1px solid #cccccc"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>The naming direction this proposal takes is to use the name <code class="sourceCode cpp">safe_range</code>, based on the existence of <code class="sourceCode cpp">safe_iterator</code> and <code class="sourceCode cpp">safe_subrange</code>. If a alternate name is preferred, the wording can simply be block replaced following the naming convention proposed in <span class="citation" data-cites="P1871R0">[<a href="#ref-P1871R0" role="doc-biblioref">P1871R0</a>]</span>. The proposal has four parts:</p>
<ul>
<li>Trait: introduce a new variable template <code class="sourceCode cpp">enable_safe_range</code>, with default value <code class="sourceCode cpp"><span class="kw">false</span><span class="op">.</span></code></li>
<li>Concept: rename the concept <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> to <code class="sourceCode cpp">safe_range</code>, make it non-exposition only, and have its definition be based on the type trait. Replace all uses of <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> with <code class="sourceCode cpp">safe_range</code> as appropriate.</li>
<li>CPO: Have <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">()</span></code>, and their const and reverse cousins, check the trait <code class="sourceCode cpp">enable_safe_range</code> and <em>only</em> allow lvalues unless this trait is true.</li>
<li>Library opt-in: Have the library types which currently opt-in to <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> by providing non-member <code class="sourceCode cpp">begin</code> and <code class="sourceCode cpp">end</code> instead specialize <code class="sourceCode cpp">enable_safe_range</code>, and remove those overloads non-member overloads.</li>
</ul>
<h2 id="wording"><span class="header-section-number">5.1</span> Wording<a href="#wording" class="self-link"></a></h2>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: The paper P1664R1 opts <code class="sourceCode cpp">iota_view</code> into modeling what is now the <code class="sourceCode cpp">safe_range</code> concept by adding non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code>. When we merge both papers together, <code class="sourceCode cpp">iota_view</code> should <em>not</em> have those non-member functions added. This paper adds the new opt-in by specializing <code class="sourceCode cpp">enable_safe_range</code>. ]</span></p>
<p>Change 21.4.1 [string.view.synop] to opt into <code class="sourceCode cpp">enable_safe_range</code>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb6"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1"></a>namespace std {</span>
<span id="cb6-2"><a href="#cb6-2"></a>  // [string.view.template], class template basic_­string_­view</span>
<span id="cb6-3"><a href="#cb6-3"></a>  template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;</span>
<span id="cb6-4"><a href="#cb6-4"></a>  class basic_string_view;</span>
<span id="cb6-5"><a href="#cb6-5"></a>  </span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="va">+ template&lt;class charT, class traits&gt;</span></span>
<span id="cb6-7"><a href="#cb6-7"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;basic_string_view&lt;charT, traits&gt;&gt; = true;  </span></span>
<span id="cb6-8"><a href="#cb6-8"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change 21.4.2 [string.view.template] to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb7"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1"></a>template&lt;class charT, class traits = char_traits&lt;charT&gt;&gt;</span>
<span id="cb7-2"><a href="#cb7-2"></a>class basic_string_view {</span>
<span id="cb7-3"><a href="#cb7-3"></a></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="st">- friend constexpr const_iterator begin(basic_string_view sv) noexcept { return sv.begin(); }</span></span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="st">- friend constexpr const_iterator end(basic_string_view sv) noexcept { return sv.end(); }</span></span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a>};</span></code></pre></div>
</div>
</blockquote>
<p>Change 22.7.2 [span.syn] to opt into <code class="sourceCode cpp">enable_safe_range</code>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb8"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1"></a>namespace std {</span>
<span id="cb8-2"><a href="#cb8-2"></a>  // constants</span>
<span id="cb8-3"><a href="#cb8-3"></a>  inline constexpr size_t dynamic_extent = numeric_limits&lt;size_t&gt;::max();</span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a>  // [views.span], class template span</span>
<span id="cb8-6"><a href="#cb8-6"></a>  template&lt;class ElementType, size_t Extent = dynamic_extent&gt;</span>
<span id="cb8-7"><a href="#cb8-7"></a>    class span;</span>
<span id="cb8-8"><a href="#cb8-8"></a>    </span>
<span id="cb8-9"><a href="#cb8-9"></a><span class="va">+ template&lt;class ElementType, size_t Extent&gt;</span></span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;span&lt;ElementType, Extent&gt;&gt; = true;    </span></span>
<span id="cb8-11"><a href="#cb8-11"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change 22.7.3.1 [span.overview] to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb9"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb9-1"><a href="#cb9-1"></a>namespace std {</span>
<span id="cb9-2"><a href="#cb9-2"></a>  template&lt;class ElementType, size_t Extent = dynamic_extent&gt;</span>
<span id="cb9-3"><a href="#cb9-3"></a>  class span {</span>
<span id="cb9-4"><a href="#cb9-4"></a>    [...]</span>
<span id="cb9-5"><a href="#cb9-5"></a>    </span>
<span id="cb9-6"><a href="#cb9-6"></a><span class="st">-   friend constexpr iterator begin(span s) noexcept { return s.begin(); }</span></span>
<span id="cb9-7"><a href="#cb9-7"></a><span class="st">-   friend constexpr iterator end(span s) noexcept { return s.end(); }</span></span>
<span id="cb9-8"><a href="#cb9-8"></a></span>
<span id="cb9-9"><a href="#cb9-9"></a>  private:</span>
<span id="cb9-10"><a href="#cb9-10"></a>    pointer data_;    // exposition only</span>
<span id="cb9-11"><a href="#cb9-11"></a>    index_type size_; // exposition only</span>
<span id="cb9-12"><a href="#cb9-12"></a>  };</span>
<span id="cb9-13"><a href="#cb9-13"></a>  </span>
<span id="cb9-14"><a href="#cb9-14"></a>  template&lt;class Container&gt;</span>
<span id="cb9-15"><a href="#cb9-15"></a>    span(const Container&amp;) -&gt; span&lt;const typename Container::value_type&gt;;</span>
<span id="cb9-16"><a href="#cb9-16"></a>}  </span></code></pre></div>
</div>
</blockquote>
<p>Change 24.2 [ranges.syn] to introduce the new trait and the new non-exposition-only concept:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb10"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb10-1"><a href="#cb10-1"></a>#include &lt;initializer_list&gt;</span>
<span id="cb10-2"><a href="#cb10-2"></a>#include &lt;iterator&gt;</span>
<span id="cb10-3"><a href="#cb10-3"></a></span>
<span id="cb10-4"><a href="#cb10-4"></a>namespace std::ranges {</span>
<span id="cb10-5"><a href="#cb10-5"></a>  [ ... ]</span>
<span id="cb10-6"><a href="#cb10-6"></a></span>
<span id="cb10-7"><a href="#cb10-7"></a>  // [range.range], ranges  </span>
<span id="cb10-8"><a href="#cb10-8"></a>  template&lt;class T&gt;</span>
<span id="cb10-9"><a href="#cb10-9"></a>    concept range = <em>see below</em>;</span>
<span id="cb10-10"><a href="#cb10-10"></a></span>
<span id="cb10-11"><a href="#cb10-11"></a><span class="va">+ template &lt;range T&gt;</span></span>
<span id="cb10-12"><a href="#cb10-12"></a><span class="va">+   inline constexpr bool enable_safe_range = false;</span></span>
<span id="cb10-13"><a href="#cb10-13"></a><span class="va">+</span></span>
<span id="cb10-14"><a href="#cb10-14"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb10-15"><a href="#cb10-15"></a><span class="va">+   concept safe_range = <em>see below</em>;</span></span>
<span id="cb10-16"><a href="#cb10-16"></a></span>
<span id="cb10-17"><a href="#cb10-17"></a>  [ ... ]    </span>
<span id="cb10-18"><a href="#cb10-18"></a>  </span>
<span id="cb10-19"><a href="#cb10-19"></a>  // [range.subrange], sub-ranges</span>
<span id="cb10-20"><a href="#cb10-20"></a>  enum class subrange_kind : bool { unsized, sized };</span>
<span id="cb10-21"><a href="#cb10-21"></a></span>
<span id="cb10-22"><a href="#cb10-22"></a>  template&lt;input_or_output_iterator I, sentinel_for&lt;I&gt; S = I, subrange_kind K = see below&gt;</span>
<span id="cb10-23"><a href="#cb10-23"></a>    requires (K == subrange_kind::sized || !sized_sentinel_for&lt;S, I&gt;)</span>
<span id="cb10-24"><a href="#cb10-24"></a>  class subrange;  </span>
<span id="cb10-25"><a href="#cb10-25"></a>  </span>
<span id="cb10-26"><a href="#cb10-26"></a><span class="va">+ template&lt;input_or_output_iterator I, sentinel_for&lt;I&gt; S, subrange_kind K&gt;</span></span>
<span id="cb10-27"><a href="#cb10-27"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;subrange&lt;I, S, K&gt;&gt; = true;  </span></span>
<span id="cb10-28"><a href="#cb10-28"></a>  </span>
<span id="cb10-29"><a href="#cb10-29"></a>  // [range.dangling], dangling iterator handling</span>
<span id="cb10-30"><a href="#cb10-30"></a>  struct dangling;</span>
<span id="cb10-31"><a href="#cb10-31"></a></span>
<span id="cb10-32"><a href="#cb10-32"></a>  template&lt;range R&gt;</span>
<span id="cb10-33"><a href="#cb10-33"></a><span class="st">-   using safe_iterator_t = conditional_t&lt;<span class="diffdel"><em>forwarding-range</em></span>&lt;R&gt;, iterator_t&lt;R&gt;, dangling&gt;;</span></span>
<span id="cb10-34"><a href="#cb10-34"></a><span class="va">+   using safe_iterator_t = conditional_t&lt;<span class="diffins">safe_range</span>&lt;R&gt;, iterator_t&lt;R&gt;, dangling&gt;;</span></span>
<span id="cb10-35"><a href="#cb10-35"></a></span>
<span id="cb10-36"><a href="#cb10-36"></a>  template&lt;range R&gt;</span>
<span id="cb10-37"><a href="#cb10-37"></a>    using safe_subrange_t =</span>
<span id="cb10-38"><a href="#cb10-38"></a><span class="st">-     conditional_t&lt;<span class="diffdel"><em>forwarding-range</em></span>&lt;R&gt;, subrange&lt;iterator_t&lt;R&gt;&gt;, dangling&gt;;</span></span>
<span id="cb10-39"><a href="#cb10-39"></a><span class="va">+     conditional_t&lt;<span class="diffins">safe_range</span>&lt;R&gt;, subrange&lt;iterator_t&lt;R&gt;&gt;, dangling&gt;;</span></span>
<span id="cb10-40"><a href="#cb10-40"></a>      </span>
<span id="cb10-41"><a href="#cb10-41"></a>  // [range.empty], empty view</span>
<span id="cb10-42"><a href="#cb10-42"></a>  template&lt;class T&gt;</span>
<span id="cb10-43"><a href="#cb10-43"></a>    requires is_object_v&lt;T&gt;</span>
<span id="cb10-44"><a href="#cb10-44"></a>  class empty_view;</span>
<span id="cb10-45"><a href="#cb10-45"></a></span>
<span id="cb10-46"><a href="#cb10-46"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb10-47"><a href="#cb10-47"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;empty_view&lt;T&gt;&gt; = true;  </span></span>
<span id="cb10-48"><a href="#cb10-48"></a>  </span>
<span id="cb10-49"><a href="#cb10-49"></a>  </span>
<span id="cb10-50"><a href="#cb10-50"></a>  [...]</span>
<span id="cb10-51"><a href="#cb10-51"></a>  </span>
<span id="cb10-52"><a href="#cb10-52"></a>  // [range.iota], iota view</span>
<span id="cb10-53"><a href="#cb10-53"></a>  template&lt;weakly_incrementable W, semiregular Bound = unreachable_sentinel_t&gt;</span>
<span id="cb10-54"><a href="#cb10-54"></a>    requires weakly-equality-comparable-with&lt;W, Bound&gt;</span>
<span id="cb10-55"><a href="#cb10-55"></a>  class iota_view;</span>
<span id="cb10-56"><a href="#cb10-56"></a>  </span>
<span id="cb10-57"><a href="#cb10-57"></a><span class="va">+ template&lt;weakly_incrementable W, semiregular Bound&gt;</span></span>
<span id="cb10-58"><a href="#cb10-58"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;iota_view&lt;W, Bound&gt;&gt; = true;  </span></span>
<span id="cb10-59"><a href="#cb10-59"></a>  </span>
<span id="cb10-60"><a href="#cb10-60"></a>  [...]</span>
<span id="cb10-61"><a href="#cb10-61"></a>  </span>
<span id="cb10-62"><a href="#cb10-62"></a>  template&lt;range R&gt;</span>
<span id="cb10-63"><a href="#cb10-63"></a>    requires is_object_v&lt;R&gt;</span>
<span id="cb10-64"><a href="#cb10-64"></a>  class ref_view;</span>
<span id="cb10-65"><a href="#cb10-65"></a>  </span>
<span id="cb10-66"><a href="#cb10-66"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb10-67"><a href="#cb10-67"></a><span class="va">+   inline constexpr bool enable_safe_range&lt;ref_view&lt;T&gt;&gt; = true;  </span></span>
<span id="cb10-68"><a href="#cb10-68"></a></span>
<span id="cb10-69"><a href="#cb10-69"></a>  [...]</span>
<span id="cb10-70"><a href="#cb10-70"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change the definitions of <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">()</span></code>, and their <code class="sourceCode cpp">c</code> and <code class="sourceCode cpp">r</code> cousins, to only allow lvalues unless <code class="sourceCode cpp">enable_safe_range</code> is <code class="sourceCode cpp"><span class="kw">true</span></code>, and then be indifferent to member vs non-member (see also <span class="citation" data-cites="stl2.429">[<a href="#ref-stl2.429" role="doc-biblioref">stl2.429</a>]</span>). The poison pill no longer needs to force an overload taking a value or rvalue reference, it now only needs to force ADL - see also <span class="citation" data-cites="LWG3247">[<a href="#ref-LWG3247" role="doc-biblioref">LWG3247</a>]</span>), but this change is not made in this paper.</p>
<p>Change. 24.3.1 [range.access.begin]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))&gt;&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​​begin<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode cpp">E <span class="op">+</span> <span class="dv">0</span></code></span> if <span><code class="sourceCode cpp">E</code></span></del></span> <span class="addu"><code class="sourceCode cpp">t <span class="op">+</span> <span class="dv">0</span></code> if <code class="sourceCode cpp">t</code></span> is <span class="rm" style="color: #bf0303"><del>an lvalue</del></span> of array type ([basic.compound]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del>if <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.begin())</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code><i>decay-copy</i>(begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code> with overload resolution performed in a context that includes the declarations:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>template&lt;class T&gt; void begin(T&amp;&amp;) = delete;</span>
<span id="cb11-2"><a href="#cb11-2"></a>template&lt;class T&gt; void begin(initializer_list&lt;T&gt;&amp;&amp;) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ Note: This case can result in substitution failure when <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. <em>— end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, its type models <code class="sourceCode cpp">input_or_output_iterator</code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.2 [range.access.end] similarly:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges​<span class="op">::</span>​end</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))&gt;&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​​end<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <code><span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span> + extent_v&lt;T&gt;</code> if <code class="sourceCode cpp">E</code> is <span class="rm" style="color: #bf0303"><del>an lvalue</del></span> of array type ([basic.compound]) <code class="sourceCode cpp">T</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del>if E is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.end())</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">))&gt;</span></code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code><i>decay-copy</i>(end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">))&gt;</span></code> with overload resolution performed in a context that includes the declarations:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb12-1"><a href="#cb12-1"></a>template&lt;class T&gt; void end(T&amp;&amp;) = delete;</span>
<span id="cb12-2"><a href="#cb12-2"></a>template&lt;class T&gt; void end(initializer_list&lt;T&gt;&amp;&amp;) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges​<span class="op">::</span>​end</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ <em>Note</em>: This case can result in substitution failure when <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, the types <code class="sourceCode cpp">S</code> and <code class="sourceCode cpp">I</code> of <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>E<span class="op">)</span></code> model <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span>S, I<span class="op">&gt;</span></code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.5 [range.access.rbegin]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))&gt;&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​​rbegin<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del>If <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.rbegin())</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <code><i>decay-copy</i>(rbegin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code> with overload resolution performed in a context that includes the declaration:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb13-1"><a href="#cb13-1"></a>template&lt;class T&gt; void rbegin(T&amp;&amp;) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code>make_reverse_iterator(ranges​::​end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if both <code>ranges​::​begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> and <code>ranges​::​end(​<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> are valid expressions of the same type <code class="sourceCode cpp">I</code> which models <code class="sourceCode cpp">bidirectional_iterator</code> ([iterator.concept.bidir]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ Note: This case can result in substitution failure when <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, its type models <code class="sourceCode cpp">input_or_output_iterator</code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.6 [range.access.rend]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))&gt;&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​​rend<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del>If <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.rend())</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">))&gt;</span></code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <code><i>decay-copy</i>(rend(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">))&gt;</span></code>. with overload resolution performed in a context that includes the declaration:</p>
<div>
<div class="sourceCode" id="cb14"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb14-1"><a href="#cb14-1"></a>template&lt;class T&gt; void rend(T&amp;&amp;) = delete;</span></code></pre></div>
</div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code>make_reverse_iterator(ranges​::​begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if both <code>ranges​::​begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> and <code>ranges​::​​end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> are valid expressions of the same type <code class="sourceCode cpp">I</code> which models <code class="sourceCode cpp">bidirectional_iterator</code> ([iterator.concept.bidir]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ <em>Note</em>: This case can result in substitution failure when <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, the types <code class="sourceCode cpp">S</code> and <code class="sourceCode cpp">I</code> of <code class="sourceCode cpp">ranges​<span class="op">::</span>​rend<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges​<span class="op">::</span>​rbegin<span class="op">(</span>E<span class="op">)</span></code> model <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span>S, I<span class="op">&gt;</span></code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.4.2 [range.range]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The <code class="sourceCode cpp">range</code> concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range.</p>
<div>
<div class="sourceCode" id="cb15"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb15-1"><a href="#cb15-1"></a><span class="st">- template&lt;class T&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2"></a><span class="st">-   concept range-impl =          // exposition only</span></span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="st">-     requires(T&amp;&amp; t) {</span></span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="st">-       ranges::begin(std::forward&lt;T&gt;(t));        // sometimes equality-preserving (see below)</span></span>
<span id="cb15-5"><a href="#cb15-5"></a><span class="st">-       ranges::end(std::forward&lt;T&gt;(t));</span></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="st">-     };</span></span>
<span id="cb15-7"><a href="#cb15-7"></a><span class="st">- </span></span>
<span id="cb15-8"><a href="#cb15-8"></a><span class="st">- template&lt;class T&gt;</span></span>
<span id="cb15-9"><a href="#cb15-9"></a><span class="st">-   concept range = <em>range-impl</em>&lt;T&amp;&gt;;</span></span>
<span id="cb15-10"><a href="#cb15-10"></a><span class="st">- </span></span>
<span id="cb15-11"><a href="#cb15-11"></a><span class="st">- template&lt;class T&gt;</span></span>
<span id="cb15-12"><a href="#cb15-12"></a><span class="st">-   concept forwarding-range =    // exposition only</span></span>
<span id="cb15-13"><a href="#cb15-13"></a><span class="st">-     range&lt;T&gt; &amp;&amp; range-impl&lt;T&gt;;</span></span>
<span id="cb15-14"><a href="#cb15-14"></a></span>
<span id="cb15-15"><a href="#cb15-15"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb15-16"><a href="#cb15-16"></a><span class="va">+   concept range =</span></span>
<span id="cb15-17"><a href="#cb15-17"></a><span class="va">+     requires(T&amp; t) {</span></span>
<span id="cb15-18"><a href="#cb15-18"></a><span class="va">+       ranges::begin(t);                         // sometimes equality-preserving (see below)</span></span>
<span id="cb15-19"><a href="#cb15-19"></a><span class="va">+       ranges::end(t);</span></span>
<span id="cb15-20"><a href="#cb15-20"></a><span class="va">+     }; </span></span>
<span id="cb15-21"><a href="#cb15-21"></a><span class="va">+</span></span>
<span id="cb15-22"><a href="#cb15-22"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb15-23"><a href="#cb15-23"></a><span class="va">+   concept safe_range =</span></span>
<span id="cb15-24"><a href="#cb15-24"></a><span class="va">+     range&lt;T&gt; &amp;&amp;</span></span>
<span id="cb15-25"><a href="#cb15-25"></a><span class="va">+       (is_lvalue_reference_v&lt;T&gt; || enable_safe_range&lt;remove_cvref_t&lt;T&gt;&gt;);</span></span></code></pre></div>
</div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span> Given an expression <code class="sourceCode cpp">E</code> such that <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))</span></code> is <code class="sourceCode cpp">T</code> <span class="rm" style="color: #bf0303"><del>and an lvalue <span><code class="sourceCode cpp">t</code></span> that denotes the same object as <span><code class="sourceCode cpp">E</code></span></del></span>, <code class="sourceCode cpp">T</code> models <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span> only if <span class="addu">the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</span></p>
<div class="rm" style="color: #bf0303">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges​<span class="op">::</span>​begin<span class="op">(</span>t<span class="op">)</span></code> are expression-equivalent,</li>
<li><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span> <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges​<span class="op">::</span>​end<span class="op">(</span>t<span class="op">)</span></code> are expression-equivalent, and</li>
<li><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span> the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</li>
</ul>

</div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span> [ <em>Note</em>: Since the validity of iterators is not tied to the lifetime of an object whose type models <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling. — <em>end note</em> ]</p>
<div>
<div class="sourceCode" id="cb16"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb16-1"><a href="#cb16-1"></a><span class="va">+ template&lt;class&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="va">+   inline constexpr bool enable_safe_range = false;</span></span></code></pre></div>
</div>
<p><span class="marginalizedparent"><a class="marginalized">6*</a></span> <span class="addu"><em>Remarks</em>: Pursuant to [namespace.std], users may specialize <code class="sourceCode cpp">enable_safe_range</code> for <em>cv</em>-unqualified program-defined types. Such specializations shall be usable in constant expressions ([expr.const]) and have type <code class="sourceCode cpp"><span class="kw">const</span> <span class="dt">bool</span></code>.</span></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span> [ Example: Specializations of class template <code class="sourceCode cpp">subrange</code> model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>. <code class="sourceCode cpp">subrange</code> <span class="rm" style="color: #bf0303"><del>provides non-member rvalue overloads of <span><code class="sourceCode cpp">begin</code></span> and <span><code class="sourceCode cpp">end</code></span> with the same semantics as its member lvalue overloads</del></span> <span class="addu">specializes <code class="sourceCode cpp">enable_safe_range</code> to <code class="sourceCode cpp"><span class="kw">true</span></code></span>, and <code class="sourceCode cpp">subrange</code>’s iterators - since they are “borrowed” from some other range - do not have validity tied to the lifetime of a subrange object. — <em>end example</em> ]</p>
</blockquote>
<p>Change 24.4.5 [range.refinements], the definition of the <code class="sourceCode cpp">viewable_range</code> concept:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span> The <code class="sourceCode cpp">viewable_range</code> concept specifies the requirements of a <code class="sourceCode cpp">range</code> type that can be converted to a <code class="sourceCode cpp">view</code> safely.</p>
<div>
<div class="sourceCode" id="cb17"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb17-1"><a href="#cb17-1"></a>  template&lt;class T&gt;</span>
<span id="cb17-2"><a href="#cb17-2"></a>    concept viewable_range =</span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="st">-     range&lt;T&gt; &amp;&amp; (<span class="diffdel"><em>forwarding-range</em></span>&lt;T&gt; || view&lt;decay_t&lt;T&gt;&gt;);</span></span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="va">+     range&lt;T&gt; &amp;&amp; (<span class="diffins">safe_range</span>&lt;T&gt; || view&lt;decay_t&lt;T&gt;&gt;);</span></span></code></pre></div>
</div>
</blockquote>
<p>Change 24.5.3 [range.subrange], to use <code class="sourceCode cpp">safe_range</code> instead of <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in, and to add a specialization for <code class="sourceCode cpp">enable_safe_range</code> which is the new opt-in:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The <code class="sourceCode cpp">subrange</code> class template combines together an iterator and a sentinel into a single object that models the <code class="sourceCode cpp">view</code> concept. Additionally, it models the <code class="sourceCode cpp">sized_range</code> concept when the final template parameter is <code class="sourceCode cpp">subrange_kind​<span class="op">::</span>​sized</code>.</p>
<div>
<div class="sourceCode" id="cb18"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb18-1"><a href="#cb18-1"></a>namespace std::ranges {</span>
<span id="cb18-2"><a href="#cb18-2"></a></span>
<span id="cb18-3"><a href="#cb18-3"></a>  template&lt;input_or_output_iterator I, sentinel_for&lt;I&gt; S = I, subrange_kind K =</span>
<span id="cb18-4"><a href="#cb18-4"></a>      sized_sentinel_for&lt;S, I&gt; ? subrange_kind::sized : subrange_kind::unsized&gt;</span>
<span id="cb18-5"><a href="#cb18-5"></a>    requires (K == subrange_kind::sized || !sized_sentinel_for&lt;S, I&gt;)</span>
<span id="cb18-6"><a href="#cb18-6"></a>  class subrange : public view_interface&lt;subrange&lt;I, S, K&gt;&gt; {</span>
<span id="cb18-7"><a href="#cb18-7"></a>  </span>
<span id="cb18-8"><a href="#cb18-8"></a>    template&lt;<em>not-same-as</em>&lt;subrange&gt; R&gt;</span>
<span id="cb18-9"><a href="#cb18-9"></a><span class="st">-     requires <span class="diffdel"><em>forwarding-range</em></span>&lt;R&gt; &amp;&amp;</span></span>
<span id="cb18-10"><a href="#cb18-10"></a><span class="va">+     requires <span class="diffins">safe_range</span>&lt;R&gt; &amp;&amp;</span></span>
<span id="cb18-11"><a href="#cb18-11"></a>        convertible_to&lt;iterator_t&lt;R&gt;, I&gt; &amp;&amp; convertible_to&lt;sentinel_t&lt;R&gt;, S&gt;</span>
<span id="cb18-12"><a href="#cb18-12"></a>    constexpr subrange(R&amp;&amp; r) requires (!StoreSize || sized_range&lt;R&gt;);</span>
<span id="cb18-13"><a href="#cb18-13"></a></span>
<span id="cb18-14"><a href="#cb18-14"></a><span class="st">-   template&lt;<span class="diffdel"><em>forwarding-range</em></span> R&gt;</span></span>
<span id="cb18-15"><a href="#cb18-15"></a><span class="va">+   template&lt;<span class="diffins">safe_range</span> R&gt;</span></span>
<span id="cb18-16"><a href="#cb18-16"></a>      requires convertible_to&lt;iterator_t&lt;R&gt;, I&gt; &amp;&amp; convertible_to&lt;sentinel_t&lt;R&gt;, S&gt;</span>
<span id="cb18-17"><a href="#cb18-17"></a>    constexpr subrange(R&amp;&amp; r, <em>make-unsigned-like-t</em>(iter_difference_t&lt;I&gt;) n)</span>
<span id="cb18-18"><a href="#cb18-18"></a>      requires (K == subrange_kind::sized)</span>
<span id="cb18-19"><a href="#cb18-19"></a>        : subrange{ranges::begin(r), ranges::end(r), n}</span>
<span id="cb18-20"><a href="#cb18-20"></a>    {}  </span>
<span id="cb18-21"><a href="#cb18-21"></a>  </span>
<span id="cb18-22"><a href="#cb18-22"></a><span class="st">-   friend constexpr I begin(subrange&amp;&amp; r) { return r.begin(); }</span></span>
<span id="cb18-23"><a href="#cb18-23"></a><span class="st">-   friend constexpr S end(subrange&amp;&amp; r) { return r.end(); }</span></span>
<span id="cb18-24"><a href="#cb18-24"></a>  };</span>
<span id="cb18-25"><a href="#cb18-25"></a></span>
<span id="cb18-26"><a href="#cb18-26"></a></span>
<span id="cb18-27"><a href="#cb18-27"></a><span class="st">- template&lt;<span class="diffdel"><em>forwarding-range</em></span> R&gt;</span></span>
<span id="cb18-28"><a href="#cb18-28"></a><span class="va">+ template&lt;<span class="diffins">safe_range</span> R&gt;</span></span>
<span id="cb18-29"><a href="#cb18-29"></a>    subrange(R&amp;&amp;) -&gt;</span>
<span id="cb18-30"><a href="#cb18-30"></a>      subrange&lt;iterator_t&lt;R&gt;, sentinel_t&lt;R&gt;,</span>
<span id="cb18-31"><a href="#cb18-31"></a>               (sized_range&lt;R&gt; || sized_sentinel_for&lt;sentinel_t&lt;R&gt;, iterator_t&lt;R&gt;&gt;)</span>
<span id="cb18-32"><a href="#cb18-32"></a>                 ? subrange_kind::sized : subrange_kind::unsized&gt;;</span>
<span id="cb18-33"><a href="#cb18-33"></a></span>
<span id="cb18-34"><a href="#cb18-34"></a><span class="st">- template&lt;<span class="diffdel"><em>forwarding-range</em></span> R&gt;</span></span>
<span id="cb18-35"><a href="#cb18-35"></a><span class="va">+ template&lt;<span class="diffins">safe_range</span> R&gt;</span></span>
<span id="cb18-36"><a href="#cb18-36"></a>    subrange(R&amp;&amp;, <em>make-unsigned-like-t</em>(range_difference_t&lt;R&gt;)) -&gt;</span>
<span id="cb18-37"><a href="#cb18-37"></a>      subrange&lt;iterator_t&lt;R&gt;, sentinel_t&lt;R&gt;, subrange_kind::sized&gt;;</span>
<span id="cb18-38"><a href="#cb18-38"></a>      </span>
<span id="cb18-39"><a href="#cb18-39"></a>  template&lt;size_t N, class I, class S, subrange_kind K&gt;</span>
<span id="cb18-40"><a href="#cb18-40"></a>    requires (N &lt; 2)</span>
<span id="cb18-41"><a href="#cb18-41"></a>  constexpr auto get(const subrange&lt;I, S, K&gt;&amp; r);  </span>
<span id="cb18-42"><a href="#cb18-42"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change the name of the concept in 24.5.3.1 [range.subrange.ctor]:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb19"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb19-1"><a href="#cb19-1"></a>  template&lt;<em>not-same-as</em>&lt;subrange&gt; R&gt;</span>
<span id="cb19-2"><a href="#cb19-2"></a><span class="st">-   requires <span class="diffdel"><em>forwarding-range</em></span>&lt;R&gt; &amp;&amp;</span></span>
<span id="cb19-3"><a href="#cb19-3"></a><span class="va">+   requires <span class="diffins">safe_range</span>&lt;R&gt; &amp;&amp;</span></span>
<span id="cb19-4"><a href="#cb19-4"></a>             convertible_to&lt;iterator_t&lt;R&gt;, I&gt; &amp;&amp; convertible_to&lt;sentinel_t&lt;R&gt;, S&gt;</span>
<span id="cb19-5"><a href="#cb19-5"></a>  constexpr subrange(R&amp;&amp; r) requires (!StoreSize || sized_range&lt;R&gt;);</span></code></pre></div>
</div>
</blockquote>
<p>Change the name of the concept in 24.5.4 [range.dangling]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The tag type <code class="sourceCode cpp">dangling</code> is used together with the template aliases <code class="sourceCode cpp">safe_iterator_t</code> and <code class="sourceCode cpp">safe_subrange_t</code> to indicate that an algorithm that typically returns an iterator into or subrange of a <code class="sourceCode cpp">range</code> argument does not return an iterator or subrange which could potentially reference a range whose lifetime has ended for a particular rvalue <code class="sourceCode cpp">range</code> argument which does not model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span> ([range.range]).</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Example</em>: […]</p>
<p>The call to <code class="sourceCode cpp">ranges​<span class="op">::</span>​find</code> at <code class="sourceCode cpp"><span class="pp">#1</span></code> returns <code class="sourceCode cpp">ranges​<span class="op">::</span>​dangling</code> since <code class="sourceCode cpp">f<span class="op">()</span></code> is an rvalue <code class="sourceCode cpp">vector</code>; the <code class="sourceCode cpp">vector</code> could potentially be destroyed before a returned iterator is dereferenced. However, the calls at <code class="sourceCode cpp"><span class="pp">#2</span></code> and <code class="sourceCode cpp"><span class="pp">#3</span></code> both return iterators since the lvalue vec and specializations of <code class="sourceCode cpp">subrange</code> model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>. — <em>end example</em> ]</p>
</blockquote>
<p>Remove the non-member old opt-ins in 24.6.1.2 [range.empty.view]:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb20"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb20-1"><a href="#cb20-1"></a>namespace std::ranges {</span>
<span id="cb20-2"><a href="#cb20-2"></a>  template&lt;class T&gt;</span>
<span id="cb20-3"><a href="#cb20-3"></a>    requires is_object_v&lt;T&gt;</span>
<span id="cb20-4"><a href="#cb20-4"></a>  class empty_view : public view_interface&lt;empty_view&lt;T&gt;&gt; {</span>
<span id="cb20-5"><a href="#cb20-5"></a>  public:</span>
<span id="cb20-6"><a href="#cb20-6"></a></span>
<span id="cb20-7"><a href="#cb20-7"></a><span class="st">-   friend constexpr T* begin(empty_view) noexcept { return nullptr; }</span></span>
<span id="cb20-8"><a href="#cb20-8"></a><span class="st">-   friend constexpr T* end(empty_view) noexcept { return nullptr; }</span></span>
<span id="cb20-9"><a href="#cb20-9"></a>  };</span>
<span id="cb20-10"><a href="#cb20-10"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Remove the non-member old opt-ins in 24.7.3.1 [range.ref.view]:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb21"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb21-1"><a href="#cb21-1"></a>namespace std::ranges {</span>
<span id="cb21-2"><a href="#cb21-2"></a>  template&lt;range R&gt;</span>
<span id="cb21-3"><a href="#cb21-3"></a>    requires is_object_v&lt;R&gt;</span>
<span id="cb21-4"><a href="#cb21-4"></a>  class ref_view : public view_interface&lt;ref_view&lt;R&gt;&gt; {</span>
<span id="cb21-5"><a href="#cb21-5"></a>  private:</span>
<span id="cb21-6"><a href="#cb21-6"></a>    R* r_ = nullptr;            // exposition only</span>
<span id="cb21-7"><a href="#cb21-7"></a>  public:</span>
<span id="cb21-8"><a href="#cb21-8"></a><span class="st">-   friend constexpr iterator_t&lt;R&gt; begin(ref_view r)</span></span>
<span id="cb21-9"><a href="#cb21-9"></a><span class="st">-   { return r.begin(); }</span></span>
<span id="cb21-10"><a href="#cb21-10"></a></span>
<span id="cb21-11"><a href="#cb21-11"></a><span class="st">-   friend constexpr sentinel_t&lt;R&gt; end(ref_view r)</span></span>
<span id="cb21-12"><a href="#cb21-12"></a><span class="st">-   { return r.end(); }</span></span>
<span id="cb21-13"><a href="#cb21-13"></a>  };</span>
<span id="cb21-14"><a href="#cb21-14"></a>  template&lt;class R&gt;</span>
<span id="cb21-15"><a href="#cb21-15"></a>    ref_view(R&amp;) -&gt; ref_view&lt;R&gt;;</span>
<span id="cb21-16"><a href="#cb21-16"></a>}</span></code></pre></div>
</div>
</blockquote>
<h1 id="acknowledgements" style="border-bottom:1px solid #cccccc"><span class="header-section-number">6</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Eric Niebler and Casey Carter for going over this paper with me, and correcting some serious misconceptions earlier drafts had. Thanks to Tim Song and Agustín Bergé for going over the details. Thanks to Tony van Eerd for helping with naming.</p>
<h1 id="references" style="border-bottom:1px solid #cccccc"><span class="header-section-number">7</span> References<a href="#references" class="self-link"></a></h1>

<div id="refs" role="doc-bibliography">
<div id="ref-LWG3247">
<p>[LWG3247] Casey Carter. ranges::iter_move should perform ADL-only lookup of iter_move. <br />
<a href="https://wg21.link/lwg3247">https://wg21.link/lwg3247</a></p>
</div>
<div id="ref-msvc.basic_string_view">
<p>[msvc.basic_string_view] non-member <code class="sourceCode cpp">begin<span class="op">()</span></code>/<code class="sourceCode cpp">end<span class="op">()</span></code> for <code class="sourceCode cpp">basic_string_view</code>. <br />
<a href="https://github.com/microsoft/STL/blame/92508bed6387cbdae433fc86279bc446af6f1b1a/stl/inc/xstring#L1207-L1216">https://github.com/microsoft/STL/blame/92508bed6387cbdae433fc86279bc446af6f1b1a/stl/inc/xstring#L1207-L1216</a></p>
</div>
<div id="ref-P0896R1">
<p>[P0896R1] Eric Niebler, Casey Carter. 2018. Merging the Ranges TS. <br />
<a href="https://wg21.link/p0896r1">https://wg21.link/p0896r1</a></p>
</div>
<div id="ref-P0970R1">
<p>[P0970R1] Eric Niebler. 2018. Better, Safer Range Access Customization Points. <br />
<a href="https://wg21.link/p0970r1">https://wg21.link/p0970r1</a></p>
</div>
<div id="ref-P1870R0">
<p>[P1870R0] Barry Revzin. 2019. forwarding-range is too subtle. <br />
<a href="https://wg21.link/p1870r0">https://wg21.link/p1870r0</a></p>
</div>
<div id="ref-P1871R0">
<p>[P1871R0] Barry Revzin. 2019. Should concepts be enabled or disabled? <br />
<a href="https://wg21.link/p1871r0">https://wg21.link/p1871r0</a></p>
</div>
<div id="ref-P1900R0">
<p>[P1900R0] Barry Revzin. 2019. Concepts-adjacent problems. <br />
<a href="https://wg21.link/p1900r0">https://wg21.link/p1900r0</a></p>
</div>
<div id="ref-stl2.429">
<p>[stl2.429] Casey Carter. 2018. Consider removing support for rvalue ranges from range access CPOs. <br />
<a href="https://github.com/ericniebler/stl2/issues/429">https://github.com/ericniebler/stl2/issues/429</a></p>
</div>
<div id="ref-stl2.547">
<p>[stl2.547] Eric Niebler. 2018. Redesign begin/end CPOs to eliminate deprecated behavior. <br />
<a href="https://github.com/ericniebler/stl2/issues/547">https://github.com/ericniebler/stl2/issues/547</a></p>
</div>
<div id="ref-stl2.592">
<p>[stl2.592] Eric Niebler. 2018. <code class="sourceCode cpp"><span class="kw">const</span> subrange<span class="op">&lt;</span>I,S,<span class="op">[</span>un<span class="op">]</span>sized<span class="op">&gt;</span></code> is not a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. <br />
<a href="https://github.com/ericniebler/stl2/issues/592">https://github.com/ericniebler/stl2/issues/592</a></p>
</div>
</div>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>There is a hypothetical kind of range where the range itself owns its data by <code class="sourceCode cpp">shared_ptr</code>, and the iterators <em>also</em> share ownership of the data. In this way, the iterators’ validity isn’t tied to the range’s lifetime not because the range doesn’t own the elements (as in the <code class="sourceCode cpp">span</code> case) but because the iterators <em>also</em> own the elements. I’m not sure if anybody has ever written such a thing.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p>I intend this as a positive, not as being derogatory.<a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
