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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/vnd.microsoft.icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Deprecate
<code class="sourceCode default">const</code>-qualifier on begin/end of
views</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P4331R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-01-13</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG9<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Jonathan Müller (think-cell)<br>&lt;<a href="mailto:foonathan@jonathanmueller.dev" class="email">foonathan@jonathanmueller.dev</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract</a></li>
<li><a href="#background" id="toc-background"><span class="toc-section-number">2</span> Background</a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation</a>
<ul>
<li><a href="#common-pitfalls-for-users" id="toc-common-pitfalls-for-users"><span class="toc-section-number">3.1</span> Common pitfalls for users</a></li>
<li><a href="#implementation-complexity" id="toc-implementation-complexity"><span class="toc-section-number">3.2</span> Implementation complexity</a></li>
<li><a href="#what-is-the-benefit-anyway" id="toc-what-is-the-benefit-anyway"><span class="toc-section-number">3.3</span> What is the benefit,
anyway?</a></li>
</ul></li>
<li><a href="#prior-discussion" id="toc-prior-discussion"><span class="toc-section-number">4</span> Prior discussion</a></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">5</span> Proposal</a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">6</span> Wording</a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">7</span> References</a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>Some views have a
<code class="sourceCode default">const</code>-qualified
<code class="sourceCode default">begin()</code> member function
(e.g. <code class="sourceCode default">transform_view</code>), while
some views do not have a
<code class="sourceCode default">const</code>-qualified member function
(e.g. <code class="sourceCode default">filter_view</code>,
<code class="sourceCode default">split_view</code>). This behavior is
confusing, as it allows beginners to write code that take an arbitrary
range by reference to <code class="sourceCode default">const</code>.
Such code works for almost all forward ranges, but not once
<code class="sourceCode default">filter_view</code>/<code class="sourceCode default">split_view</code>/…
is added into the mix, or input ranges. We propose deprecating the
<code class="sourceCode default">const</code> qualifier to ensure that
<strong>no</strong> view is
<code class="sourceCode default">const</code>-iteratable and not adding
it to all future views.</p>
<h1 data-number="2" id="background"><span class="header-section-number">2</span> Background<a href="#background" class="self-link"></a></h1>
<p>A <code class="sourceCode default">view</code> is a light-weight
non-owning (mostly) cheaply copyable (mostly) range. Conceptually, a
<code class="sourceCode default">view</code> is like a smart reference
to a container: copying a <code class="sourceCode default">view</code>
does not copy the container, a
<code class="sourceCode default">const view</code> does not provide
<code class="sourceCode default">const</code> element access, etc. —
they have reference semantics. For types with reference semantics there
are two levels on <code class="sourceCode default">const</code>: whether
the reference itself is <code class="sourceCode default">const</code>
and cannot be changed or whether the referenced data is
<code class="sourceCode default">const</code>. This distinction matters,
and just like with pointers, where we have
<code class="sourceCode default">T const*</code> and
<code class="sourceCode default">T* const</code>, the two should not be
confused.</p>
<p>Right now, most views in the standard library have a
<code class="sourceCode default">const</code> qualified
<code class="sourceCode default">begin()</code> member function, as they
just return an iterator without doing mutation. This follows the general
philosophy of making things
<code class="sourceCode default">const</code>-qualified whenever
possible. There are two kinds of views that don’t have it:</p>
<ol type="1">
<li>Input views where calling
<code class="sourceCode default">begin()</code> permanently consumes
some data
(e.g. <code class="sourceCode default">std::generator</code>).</li>
<li>Forward views where calling
<code class="sourceCode default">begin()</code> does some computation
which is then cached to require the O(1) amortized complexity of
<code class="sourceCode default">begin()</code>
(e.g. <code class="sourceCode default">filter_view</code>,
<code class="sourceCode default">split_view</code>, views wrapping
<code class="sourceCode default">filter_view</code>/<code class="sourceCode default">split_view</code>/…).</li>
</ol>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<h2 data-number="3.1" id="common-pitfalls-for-users"><span class="header-section-number">3.1</span> Common pitfalls for users<a href="#common-pitfalls-for-users" class="self-link"></a></h2>
<p>While the philosophy of making things
<code class="sourceCode default">const</code>-qualified whenever
possible is good in most situations, with views specifically it has
created problems. Views look like containers but absolutely are not
containers. The following code, while looking sensible at first, should
be considered bad practice:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Rng<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> do_something<span class="op">(</span><span class="kw">const</span> Rng<span class="op">&amp;</span> rng<span class="op">)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> x <span class="op">:</span> rng<span class="op">)</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        …</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The user has <code class="sourceCode default">const</code>-qualified
the reference, since they don’t want to change the values of the range,
only process it. This logic is sound for containers, which have value
semantics, but not for views, which have reference semantics. For views,
<code class="sourceCode default">x</code> is not
<code class="sourceCode default">const</code>: the const-ness of a view
is independent of the const-ness of the elements. Furthermore, this
function breaks as soon as e.g. a
<code class="sourceCode default">filter_view</code>/<code class="sourceCode default">split_view</code>/…
is involved.</p>
<p>The correct version takes the
<code class="sourceCode default">Rng</code> by forwarding reference and
manually ensures it is <code class="sourceCode default">const</code> in
the body:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Rng<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> do_something<span class="op">(</span>Rng<span class="op">&amp;&amp;</span> rng<span class="op">)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> x <span class="op">:</span> rng<span class="op">)</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        …</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Thus, <strong>no <em>generic</em> function that takes an
<em>arbitrary</em>
<code class="sourceCode default">const Rng&amp;</code> is
correct</strong>. We should want to discourage people from writing code
like that by having it fail earlier.</p>
<h2 data-number="3.2" id="implementation-complexity"><span class="header-section-number">3.2</span> Implementation complexity<a href="#implementation-complexity" class="self-link"></a></h2>
<p>If a view is never <code class="sourceCode default">const</code>
iteratable, the implementation is easy: just provide a single
<code class="sourceCode default">begin()</code>/<code class="sourceCode default">end()</code>.
But if a view is <code class="sourceCode default">const</code>
iteratable if the base view is
<code class="sourceCode default">const</code> iteratable, you need to
provide two overloads: one for
<code class="sourceCode default">const</code> and one for
non-<code class="sourceCode default">const</code>; the latter only
conditionally available. This is more work than only providing a
non-<code class="sourceCode default">const</code> qualified view
object.</p>
<h2 data-number="3.3" id="what-is-the-benefit-anyway"><span class="header-section-number">3.3</span> What is the benefit, anyway?<a href="#what-is-the-benefit-anyway" class="self-link"></a></h2>
<p>What do you get from having a view that is
<code class="sourceCode default">const</code> iteratable? The only
benefit is that you can actually use a
<code class="sourceCode default">const</code> view to do iteration.</p>
<p>But why would you want a
<code class="sourceCode default">const</code> view? What does the
<code class="sourceCode default">const</code> qualifier get you? Only
two things:</p>
<ol type="1">
<li>You have a tool to prevent accidentally re-assigning your view
object to point to different data.</li>
<li>You can share your view objects between threads and have a guarantee
that there are no data races.</li>
</ol>
<p>Crucially, it does not guarantee that the underlying elements are
<code class="sourceCode default">const</code>!</p>
<p>For a view like <code class="sourceCode default">std::span</code> or
<code class="sourceCode default">std::string_view</code>, the benefits
make sense: They are vocabulary types that might appear in a global
variable or in complex code where you would want to prevent accidental
reassignment.</p>
<p>However, this is not really useful for a view adaptor from
<code class="sourceCode default">std::ranges</code>:</p>
<ol type="1">
<li>Views can only be assigned to an object of the same type. For a view
adaptor, this type depends on a lambda, so it actually requires some
effort to even have a situation where you have two different views of
the same type that you could potentially re-assign to each other. And
even if you end up in a situation, e.g. by having a factory function
that returns a view given some range and you call it with two different
ranges of the same type, why is there code that even attempts to do
assignment of views? Views are meant to be created on the fly, to
iterate over some code, not stored in variables.</li>
<li>What is the use case for sharing views between threads? Views are
cheap to construct, so you can always share your data and create
separate view objects in each thread.</li>
</ol>
<p>We argue that allowing <code class="sourceCode default">const</code>
qualified view adaptors has only marginal benefits for increased
implementation complexity. The main feature of
<code class="sourceCode default">const</code> qualified view adaptors is
enabling a pitfall for beginners.</p>
<h1 data-number="4" id="prior-discussion"><span class="header-section-number">4</span> Prior discussion<a href="#prior-discussion" class="self-link"></a></h1>
<p>The need for <code class="sourceCode default">const</code>-qualified
<code class="sourceCode default">begin()</code>/<code class="sourceCode default">end()</code>
on views has been discussed back in 2016 in <span class="citation" data-cites="range-v3">[<a href="#ref-range-v3" role="doc-biblioref">range-v3</a>]</span> <span class="citation" data-cites="range-v3-discussion">[<a href="#ref-range-v3-discussion" role="doc-biblioref">range-v3-discussion</a>]</span>. It raised similar
points as in this paper:</p>
<p><a href="https://github.com/ericniebler/range-v3/issues/385#issue-157787516">Casey
Carter</a>:</p>
<blockquote>
<p>Views in range-v3 may have both const and non-const overloads of
begin/end/size (herein termed “operations”). Views have pointer
semantics - a view is essentially a pointer to a sequence of elements -
so mutability of the elements viewed is orthogonal to mutability of the
view object itself. The const distinction here has no relation to that
of containers. Non-const operations do not modify the semantic objects
being viewed, nor do they “swing the pointer” so that the same view
designates different semantic objects. Non-const operations mutate
internal state that does not contribute to the semantic value of the
view; the const-ness here is purely bitwise.</p>
<p>The const-ness model used by views makes view composition painful.
[…] I see a potential for latent bugs where a programmer accustomed to
the fact that calling begin/end on mutable containers is threadsafe
calls begin/end on mutable ranges without realizing there are sharp
corners here. […]</p>
</blockquote>
<p><a href="https://github.com/ericniebler/range-v3/issues/385#issuecomment-223640608">Eric
Niebler</a>:</p>
<blockquote>
<p>One simplification is that no views have const begin()/end() members.
That way nobody has to think about it. Seems like a fool’s consistency
to me, though.</p>
</blockquote>
<p><a href="https://github.com/ericniebler/range-v3/issues/385#issuecomment-290068388">Gonzalo
Brito Gadeschi</a>:</p>
<blockquote>
<p>The root of the problem is that newcomers try to make views consts or
try to pass them by const lvalue reference because they have an
incomplete mental model of how views work.</p>
</blockquote>
<p><a href="https://github.com/ericniebler/range-v3/issues/385#issuecomment-290196550">Eric
Niebler</a></p>
<blockquote>
<blockquote>
<p>Although he originally said it in jest, I think that ericniebler’s
suggestion upthread that maybe NO views should be const iterable may be
the best solution to user confusion about which views are const iterable
and why.</p>
</blockquote>
<p>I wasn’t joking when I said that. It’s still an attractive
option.</p>
</blockquote>
<p>Ultimately, a lot of the discussion focused around the need for
caching in <code class="sourceCode default">begin()</code>, whether that
should be <code class="sourceCode default">mutable</code> and locking,
or non-<code class="sourceCode default">const</code>, that
<code class="sourceCode default">Rng&amp;&amp;</code> is really the best
way to pass in a view and not
<code class="sourceCode default">const Rng&amp;</code>, and the
reference semantics of views. In the end, the design where caching was
done in a non-const qualified
<code class="sourceCode default">begin()</code> was chosen, and other
views are <code class="sourceCode default">const</code>-iteratable
whenever possible. The idea of omitting
<code class="sourceCode default">const</code> was not seriously
investigated, as far as we can tell.</p>
<h1 data-number="5" id="proposal"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>We propose deprecating the
<code class="sourceCode default">const</code> qualifier on
<code class="sourceCode default">begin()</code>/<code class="sourceCode default">end()</code>
of the standard library views (and consequently also on
<code class="sourceCode default">empty()</code>,
<code class="sourceCode default">size()</code> and all other member
functions that you’d get by inheriting from
<code class="sourceCode default">std::ranges::view_interface</code>).
This deprecation affects code in two situations:</p>
<ol type="1">
<li>Non-generic/non-type-inferred code that have a
<code class="sourceCode default">const view&amp;</code>, where
<code class="sourceCode default">view</code> is the concrete type of a
<code class="sourceCode default">view</code>. It will call the
<code class="sourceCode default">const</code> qualified member
functions, which will be deprecated. However, we only propose
deprecating it for the
<code class="sourceCode default">std::views</code> range adaptors, where
the name of the type is long and involves lambda, so not a lot of code
exists.</li>
<li>Generic code/type inferred code that uses
<code class="sourceCode default">const auto&amp;</code>. However, such
code would be broken as soon as a type like
<code class="sourceCode default">filter_view</code>/<code class="sourceCode default">split_view</code>/…
is involved anyway, and breaking it earlier is the primary motivation of
this paper.</li>
</ol>
<p>We also propose only deprecation and not removal, and implementations
are free to deal with the deprecation in an appropriate way.</p>
<p>Concretely, we consider the following set of
<code class="sourceCode default">const</code> qualified overloads of
member functions (when present):</p>
<ul>
<li><code class="sourceCode default">begin()</code></li>
<li><code class="sourceCode default">end()</code></li>
<li><code class="sourceCode default">empty()</code></li>
<li><code class="sourceCode default">cbegin()</code></li>
<li><code class="sourceCode default">cend()</code></li>
<li><code class="sourceCode default">operator bool()</code></li>
<li><code class="sourceCode default">data()</code></li>
<li><code class="sourceCode default">size()</code></li>
<li><code class="sourceCode default">front()</code></li>
<li><code class="sourceCode default">back()</code></li>
<li><code class="sourceCode default">operator[]</code></li>
</ul>
<p>And we propose deprecating it on the following standard library
types:</p>
<ul>
<li><code class="sourceCode default">std::ranges::ref_view</code></li>
<li><code class="sourceCode default">std::ranges::owning_view</code></li>
<li><code class="sourceCode default">std::ranges::as_rvalue_view</code></li>
<li><code class="sourceCode default">std::ranges::transform_view</code></li>
<li><code class="sourceCode default">std::ranges::take_view</code></li>
<li><code class="sourceCode default">std::ranges::take_while_view</code></li>
<li><code class="sourceCode default">std::ranges::drop_view</code></li>
<li><code class="sourceCode default">std::ranges::drop_while_view</code></li>
<li><code class="sourceCode default">std::ranges::join_view</code></li>
<li><code class="sourceCode default">std::ranges::join_with_view</code></li>
<li><code class="sourceCode default">std::ranges::lazy_split_view</code></li>
<li><code class="sourceCode default">std::ranges::common_view</code></li>
<li><code class="sourceCode default">std::ranges::reverse_view</code></li>
<li><code class="sourceCode default">std::ranges::as_const_view</code></li>
<li><code class="sourceCode default">std::ranges::elements_view</code></li>
<li><code class="sourceCode default">std::ranges::enumerate_view</code></li>
<li><code class="sourceCode default">std::ranges::zip_view</code></li>
<li><code class="sourceCode default">std::ranges::zip_transform_view</code></li>
<li><code class="sourceCode default">std::ranges::adjacent_view</code></li>
<li><code class="sourceCode default">std::ranges::adjacent_transform_view</code></li>
<li><code class="sourceCode default">std::ranges::chunk_view</code></li>
<li><code class="sourceCode default">std::ranges::slide_view</code></li>
<li><code class="sourceCode default">std::ranges::cartesian_product_view</code></li>
<li><code class="sourceCode default">std::ranges::concat_view</code></li>
</ul>
<p>We do not propose deprecating or removing it on the following
standard library types:</p>
<ul>
<li><code class="sourceCode default">std::span</code>/<code class="sourceCode default">std::string_view</code>
(it is a widely used, potentially re-assigned types where we would break
code)</li>
<li><code class="sourceCode default">std::ranges::view_interface</code>
(used by views below)</li>
<li><code class="sourceCode default">std::ranges::iota_view</code> (it
is a factory with a reasonable type name)</li>
<li><code class="sourceCode default">std::ranges::repeat_view</code> (it
is a factory with a reasonable type name)</li>
<li><code class="sourceCode default">std::ranges::empty_view</code> (the
member functions are
<code class="sourceCode default">static</code>)</li>
<li><code class="sourceCode default">std::ranges::single_view</code> (it
actually has deep <code class="sourceCode default">const</code>)</li>
</ul>
<p>Note that the following standard library types are views without
<code class="sourceCode default">const</code> qualified versions of
those member functions to begin with. As soon as code uses them with a
<code class="sourceCode default">const</code> qualifier, it will
break:</p>
<ul>
<li><code class="sourceCode default">std::ranges::istream_view</code></li>
<li><code class="sourceCode default">std::ranges::filter_view</code></li>
<li><code class="sourceCode default">std::ranges::split_view</code></li>
<li><code class="sourceCode default">std::ranges::chunk_by_view</code></li>
<li><code class="sourceCode default">std::ranges::stride_view</code></li>
<li><code class="sourceCode default">std::generator</code></li>
</ul>
<p>If a standard library types models
<code class="sourceCode default">view</code> and is not mentioned in any
list, we have forgotten about it.</p>
<h1 data-number="6" id="wording"><span class="header-section-number">6</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>TBD</p>
<h1 data-number="7" id="bibliography"><span class="header-section-number">7</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list">
<div id="ref-range-v3" class="csl-entry" role="listitem">
[range-v3] range-v3. <a href="https://github.com/ericniebler/range-v3"><div class="csl-block">https://github.com/ericniebler/range-v3</div></a>
</div>
<div id="ref-range-v3-discussion" class="csl-entry" role="listitem">
[range-v3-discussion] const-ness of view operations. <a href="https://github.com/ericniebler/range-v3/issues/385"><div class="csl-block">https://github.com/ericniebler/range-v3/issues/385</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
