<!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="2021-08-15" />
  <title>What is a `view`?</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.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      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 { 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. { } /* 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; }
</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; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
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/x-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">What is a <code class="sourceCode cpp">view</code>?</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2415R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-08-15</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>
      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>
      Tim Song<br>&lt;<a href="mailto:t.canens.cpp@gmail.com" class="email">t.canens.cpp@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="#the-need-for-cheap-copies"><span class="toc-section-number">3</span> The need for cheap copies<span></span></a></li>
<li><a href="#refining-the-view-requirements"><span class="toc-section-number">4</span> Refining the view requirements<span></span></a></li>
<li><a href="#what-is-a-view"><span class="toc-section-number">5</span> What is a <code class="sourceCode cpp">view</code>?<span></span></a></li>
<li><a href="#implementation-experience"><span class="toc-section-number">6</span> Implementation Experience<span></span></a></li>
<li><a href="#proposed-wording"><span class="toc-section-number">7</span> Proposed Wording<span></span></a></li>
<li><a href="#bibliography"><span class="toc-section-number">8</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P2415R0">[<a href="#ref-P2415R0" role="doc-biblioref">P2415R0</a>]</span>, added wording.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>C++20 Ranges introduced two main concepts for dealing with ranges: <code class="sourceCode cpp">range</code> and <code class="sourceCode cpp">view</code>. These notions were introduced way back in the original paper, “Ranges for the Standard Library” <span class="citation" data-cites="N4128">[<a href="#ref-N4128" role="doc-biblioref">N4128</a>]</span> (though under different names than what we have now - what we now know as <code class="sourceCode cpp">range</code> and <code class="sourceCode cpp">view</code> were originally specified as <code class="sourceCode cpp">Iterable</code> and <code class="sourceCode cpp">Range</code><a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>):</p>
<div class="quote">
<p>[A Range] type is one for which we can call <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> to yield an iterator/sentinel pair. (Sentinels are described below.) The [Range] concept says nothing about the type’s constructibility or assignability. Range-based standard algorithms are constrained using the [Range] concept.</p>
<p>[…]</p>
<p>The [View] concept is modeled by lightweight objects that denote a range of elements they do not own. A pair of iterators can be a model of [View], whereas a <code class="sourceCode cpp">vector</code> is not. [View], as opposed to [Range], requires copyability and assignability. Copying and assignment are required to execute in constant time; that is, the cost of these operations is not proportional to the number of elements in the Range.</p>
<p>The [View] concept refines the [Range] concept by additionally requiring following valid expressions for an object <code class="sourceCode cpp">o</code> of type <code class="sourceCode cpp">O</code>:</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="co">// Constructible:</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">auto</span> o1 <span class="op">=</span> o;</span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="kw">auto</span> o2 <span class="op">=</span> std<span class="op">::</span>move<span class="op">(</span>o<span class="op">)</span>;</span>
<span id="cb1-4"><a href="#cb1-4"></a>O o3; <span class="co">// default-constructed, singular</span></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="co">// Assignable:</span></span>
<span id="cb1-6"><a href="#cb1-6"></a>o2 <span class="op">=</span> o1;</span>
<span id="cb1-7"><a href="#cb1-7"></a>o2 <span class="op">=</span> std<span class="op">::</span>move<span class="op">(</span>o1<span class="op">)</span>;</span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="co">// Destructible</span></span>
<span id="cb1-9"><a href="#cb1-9"></a>o<span class="op">.~</span>O<span class="op">()</span>;</span></code></pre></div>
<p>The [View] concept exists to give the range adaptors consistent and predictable semantics, and memory and performance characteristics. Since adaptors allow the composition of range objects, those objects must be efficiently copyable (or at least movable). The result of adapting a [View] is a [View]. The result of adapting a container is also a [View]; the container – or any [Range] that is not already a [View] – is first converted to a [View] automatically by taking the container’s <code class="sourceCode cpp">begin</code> and <code class="sourceCode cpp">end</code>.</p>
</div>
<p>The paper really stresses two points throughout:</p>
<ul>
<li>views are lightweight objects that refer to elements they do not own<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a></li>
<li>views are O(1) copyable and assignable</li>
</ul>
<p>This design got muddled a bit when views ceased to require copyability, as a result of “Move-only Views” <span class="citation" data-cites="P1456R1">[<a href="#ref-P1456R1" role="doc-biblioref">P1456R1</a>]</span>. As the title suggests, this paper relaxed the requirement that views be copyable, and got us to the set of requirements we have now in <span>24.4.4
 <a href="https://wg21.link/range.view">[range.view]</a></span>:</p>
<ul>
<li>views are O(1) move constructible, move assignable, and destructible</li>
<li>views are either O(1) copy constructible/assignable or not copy constructible/assignable</li>
</ul>
<p>But somehow absent from the discussion is: why do we care about views and range adaptors being cheap to copy and assign and destroy? This isn’t just idle navel-gazing either, <span class="citation" data-cites="LWG3452">[<a href="#ref-LWG3452" role="doc-biblioref">LWG3452</a>]</span> points out that requiring strict O(1) destruction has implications for whether <code class="sourceCode cpp">std<span class="op">::</span>generator</code> <span class="citation" data-cites="P2168R3">[<a href="#ref-P2168R3" role="doc-biblioref">P2168R3</a>]</span> can be a <code class="sourceCode cpp">view</code>. What can go wrong in a program that annotates a range as being a <code class="sourceCode cpp">view</code> despite not meeting these requirements?</p>
<p>The goal of this paper is to provide good answers to these questions.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="the-need-for-cheap-copies"><span class="header-section-number">3</span> The need for cheap copies<a href="#the-need-for-cheap-copies" class="self-link"></a></h1>
<p>N4128 asked the following question:</p>
<div class="quote">
<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">auto</span> rng <span class="op">=</span> v <span class="op">|</span> view<span class="op">::</span>reverse;</span></code></pre></div>
<p>This creates a view of <code class="sourceCode cpp">v</code> that iterates in reverse order. Now: is <code class="sourceCode cpp">rng</code> copyable, and if so, how expensive is the copy operation?</p>
</div>
<p>Why is this question important? The initial thought to <code class="sourceCode cpp">rng</code> itself being cheap to copy might be that we need this requirement because we write algorithms that take views by value:</p>
<blockquote>
<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">template</span> <span class="op">&lt;</span>input_view V<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="dt">void</span> some_algo<span class="op">(</span>V v<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>We could have gone that route (and we definitely do encourage people to take <em>specific</em> views by value - such as <code class="sourceCode cpp">span</code> and <code class="sourceCode cpp">string_view</code>), but that would affect the usability of range-based algorithms. You could not write <code class="sourceCode cpp">ranges<span class="op">::</span>sort<span class="op">(</span>v<span class="op">)</span></code> on a <code class="sourceCode cpp">vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, since that is not a view - you would have to write <code class="sourceCode cpp">ranges<span class="op">::</span>sort<span class="op">(</span>views<span class="op">::</span>all<span class="op">(</span>v<span class="op">))</span></code> or perhaps something like <code class="sourceCode cpp">ranges<span class="op">::</span>sort<span class="op">(</span>v<span class="op">.</span>all<span class="op">())</span></code> or <code class="sourceCode cpp">ranges<span class="op">::</span>sort<span class="op">(</span>v<span class="op">.</span>view<span class="op">())</span></code>. Either way, we very much want range-based algorithms to be able to operate on, well, ranges, so these are always written instead to take ranges by forwarding reference:</p>
<blockquote>
<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">template</span> <span class="op">&lt;</span>input_range R<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="dt">void</span> some_algo<span class="op">(</span>R<span class="op">&amp;&amp;</span> r<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>At best, we write algorithms that do require views and it’s those algorithms that themselves construct the views that they need - but their API surface still takes ranges (specifically, <code class="sourceCode cpp">viewable_range</code>s <span>24.4.5
 <a href="https://wg21.link/range.refinements">[range.refinements]</a></span>) by forwarding reference.</p>
<p>If we don’t care about views being cheap to copy because of the desire to write algorithms that take them by value, then why do we care about views being cheap to copy?</p>
<p>Because we very much care about views being cheap to <em>construct</em>.</p>
<p>Let’s go back to this example:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">auto</span> rng <span class="op">=</span> v <span class="op">|</span> views<span class="op">::</span>reverse;</span></code></pre></div>
</blockquote>
<p>This is intended to be a lazy range adaptor - constructing <code class="sourceCode cpp">rng</code> here isn’t intended to do any work, it’s just preparing to do work in the future. It’s important for this to be “cheap” - in the sense that this should absolutely not end up copying all the elements of <code class="sourceCode cpp">v</code>, or really doing any operation on the elements of <code class="sourceCode cpp">v</code>. This extends to all layering of range adaptors:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">auto</span> rng <span class="op">=</span> v <span class="op">|</span> views<span class="op">::</span>some</span>
<span id="cb6-2"><a href="#cb6-2"></a>             <span class="op">|</span> views<span class="op">::</span>operations</span>
<span id="cb6-3"><a href="#cb6-3"></a>             <span class="op">|</span> views<span class="op">::</span>here;</span></code></pre></div>
</blockquote>
<p>If constructing each of these range adaptors in turn required touching all the elements of <code class="sourceCode cpp">v</code>, this would be a horribly expensive construct - and we haven’t even done anything yet! This is why we need views to be cheap to copy - range adaptors <em>are</em> the algorithms for views, and we need to be able to pass views cheaply to those.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="refining-the-view-requirements"><span class="header-section-number">4</span> Refining the view requirements<a href="#refining-the-view-requirements" class="self-link"></a></h1>
<p>Currently, in order for a type <code class="sourceCode cpp">T</code> to model <code class="sourceCode cpp">view</code>, it needs to have O(1) move construction, move assignment, and destruction. If <code class="sourceCode cpp">T</code> is copyable, the copy operations also need to be O(1). What happens if a type <code class="sourceCode cpp">T</code> satisfies <code class="sourceCode cpp">view</code> (whether by it inheriting from <code class="sourceCode cpp">view_base</code>, inheriting from <code class="sourceCode cpp">view_interface<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, or simply specializing <code class="sourceCode cpp">enable_view<span class="op">&lt;</span>T<span class="op">&gt;</span></code> to be <code class="sourceCode cpp"><span class="kw">true</span></code>), yet does not actually satisfy the O(1) semantics I just laid out?</p>
<p>Consider:</p>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">struct</span> bad_view <span class="op">:</span> view_interface<span class="op">&lt;</span>bad_view<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v;</span>
<span id="cb7-3"><a href="#cb7-3"></a>    </span>
<span id="cb7-4"><a href="#cb7-4"></a>    bad_view<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v<span class="op">)</span> <span class="op">:</span> v<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>v<span class="op">))</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb7-5"><a href="#cb7-5"></a>    </span>
<span id="cb7-6"><a href="#cb7-6"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator begin<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> v<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator end<span class="op">()</span>   <span class="op">{</span> <span class="cf">return</span> v<span class="op">.</span>end<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="op">}</span>;</span>
<span id="cb7-9"><a href="#cb7-9"></a></span>
<span id="cb7-10"><a href="#cb7-10"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> get_ints<span class="op">()</span>;</span>
<span id="cb7-11"><a href="#cb7-11"></a></span>
<span id="cb7-12"><a href="#cb7-12"></a><span class="kw">auto</span> rng <span class="op">=</span> bad_view<span class="op">(</span>get_ints<span class="op">())</span> <span class="op">|</span> views<span class="op">::</span>enumerate;</span>
<span id="cb7-13"><a href="#cb7-13"></a><span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> <span class="op">[</span>idx, i<span class="op">]</span> <span class="op">:</span> rng<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-14"><a href="#cb7-14"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}. {}</span><span class="sc">\n</span><span class="st">&quot;</span>, idx, i<span class="op">)</span>;</span>
<span id="cb7-15"><a href="#cb7-15"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">bad_view</code> is, as the name might suggest, a bad view. It is O(1) move constructible and move assignable, but it is not O(1) destructible. It is copyable, but not O(1) copyable (though nothing in this program tries to copy a <code class="sourceCode cpp">bad_view</code> - but if it did, that would be expensive!). As a result, this program is violating <span>16.4.5.11
 <a href="https://wg21.link/res.on.requirements">[res.on.requirements]</a></span>/2:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> If the validity or meaning of a program depends on whether a sequence of template arguments models a concept, and the concept is satisfied but not modeled, the program is ill-formed, no diagnostic required.</p>
</blockquote>
<p>Ill-formed, no diagnostic required! That is a harsh ruling for this program!</p>
<p>But what actually goes wrong if a program-defined <code class="sourceCode cpp">view</code> ends up violating the semantic requirements of a <code class="sourceCode cpp">view</code>? The goal of a <code class="sourceCode cpp">view</code> is to enable cheap construction of range adaptors. If that construction isn’t as cheap as expected, then the result is just that the construction is… more expensive than expected. It would still be semantically <em>correct</em>, it’s just less efficient than ideal? That’s not usually the line to draw for ill-formed, no diagnostic required.</p>
<p>Furthermore, what actual operations do we need to be cheap? Consider this refinement:</p>
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">struct</span> bad_view2 <span class="op">:</span> view_interface<span class="op">&lt;</span>bad_view2<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v;</span>
<span id="cb8-3"><a href="#cb8-3"></a>    </span>
<span id="cb8-4"><a href="#cb8-4"></a>    bad_view2<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v<span class="op">)</span> <span class="op">:</span> v<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>v<span class="op">))</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb8-5"><a href="#cb8-5"></a>    </span>
<span id="cb8-6"><a href="#cb8-6"></a>    <span class="co">// movable, but not copyable</span></span>
<span id="cb8-7"><a href="#cb8-7"></a>    bad_view2<span class="op">(</span>bad_view2 <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb8-8"><a href="#cb8-8"></a>    bad_view2<span class="op">(</span>bad_view2<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-9"><a href="#cb8-9"></a>    bad_view2<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>bad_view2 <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb8-10"><a href="#cb8-10"></a>    bad_view2<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">+(</span>bad_view2<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a>    </span>
<span id="cb8-12"><a href="#cb8-12"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator begin<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> v<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb8-13"><a href="#cb8-13"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator end<span class="op">()</span>   <span class="op">{</span> <span class="cf">return</span> v<span class="op">.</span>end<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb8-14"><a href="#cb8-14"></a><span class="op">}</span>;</span>
<span id="cb8-15"><a href="#cb8-15"></a></span>
<span id="cb8-16"><a href="#cb8-16"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> get_ints<span class="op">()</span>;</span>
<span id="cb8-17"><a href="#cb8-17"></a></span>
<span id="cb8-18"><a href="#cb8-18"></a><span class="kw">auto</span> rng <span class="op">=</span> bad_view2<span class="op">(</span>get_ints<span class="op">())</span></span>
<span id="cb8-19"><a href="#cb8-19"></a>         <span class="op">|</span> views<span class="op">::</span>filter<span class="op">([](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i <span class="op">&gt;</span> <span class="dv">0</span>; <span class="op">})</span></span>
<span id="cb8-20"><a href="#cb8-20"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i <span class="op">*</span> i; <span class="op">})</span>;</span></code></pre></div>
</blockquote>
<p>This whole construction involves moving a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> twice (once into the <code class="sourceCode cpp">filter_view</code> and once into the <code class="sourceCode cpp">transform_view</code>, both moving a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> is cheap) and destroying a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> three times (twice when the source is empty, and once eventually when we’re destroying <code class="sourceCode cpp">rng</code> - it’s this last one that is not O(1)).</p>
<p>In contrast, the ordained method for writing this code is actually:</p>
<blockquote>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">auto</span> ints <span class="op">=</span> get_ints<span class="op">()</span>; <span class="co">// must stash this into a variable first</span></span>
<span id="cb9-2"><a href="#cb9-2"></a><span class="kw">auto</span> rng <span class="op">=</span> ints</span>
<span id="cb9-3"><a href="#cb9-3"></a>         <span class="op">|</span> views<span class="op">::</span>filter<span class="op">([](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i <span class="op">&gt;</span> <span class="dv">0</span>; <span class="op">})</span></span>
<span id="cb9-4"><a href="#cb9-4"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i <span class="op">*</span> i; <span class="op">})</span>;</span></code></pre></div>
</blockquote>
<p>Now, this no longer involves any moves of a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>, since <code class="sourceCode cpp">rng</code> will instead be holding a <code class="sourceCode cpp">ref_view</code> into it, so this is in some sense cheaper. But this still, in the end, requires destroying that <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> - it’s just that this cost is paid by destroying <code class="sourceCode cpp">ints</code> rather than destroying <code class="sourceCode cpp">rng</code> in this formulation. That’s not meaningfully different. And moreover, there’s real cost to be paid by the latter formulation: now <code class="sourceCode cpp">rng</code> has an internal reference into <code class="sourceCode cpp">ints</code>, which both means that we have to be more careful because we can dangle (not an issue in the <code class="sourceCode cpp">bad_view2</code> formulation) and that we have an extra indirection through a pointer which could have performance impact.</p>
<p>Which is ironic, given that it’s the performance consideration which makes <code class="sourceCode cpp">bad_view2</code> bad.</p>
<p>Let’s consider relaxing the requirements as follows:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> <code class="sourceCode cpp">T</code> models <code class="sourceCode cpp">view</code> only if:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> <code class="sourceCode cpp">T</code> has O(1) move construction; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> <code class="sourceCode cpp">T</code> has O(1) move assignment; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span> has O(1) destruction</del></span> <span class="addu">if <code class="sourceCode cpp">N</code> moves are made from an object of type <code class="sourceCode cpp">T</code> that contained <code class="sourceCode cpp">M</code> elements, then those <code class="sourceCode cpp">N</code> objects have <code class="sourceCode cpp">O<span class="op">(</span>N<span class="op">+</span>M<span class="op">)</span></code> destruction</span>; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span> <code class="sourceCode cpp">copy_constructible<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, or <code class="sourceCode cpp">T</code> has O(1) copy construction; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span> <code class="sourceCode cpp">copyable<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, or <code class="sourceCode cpp">T</code> has O(1) copy assignment.</li>
</ul>
</blockquote>
<p>Or, alternatively:</p>
<blockquote>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span> has</del></span> <span class="addu">an object of type <code class="sourceCode cpp">T</code> that has been moved from</span> has O(1) destruction; and</li>
</ul>
</blockquote>
<p>In this formulation, <code class="sourceCode cpp">bad_view</code> is still a bad view (because it is copyable and copying it is expensive - which is important because building up a range adaptor pipeline using lvalue views will try to copy them) but <code class="sourceCode cpp">bad_view2</code> is actually totally fine (and indeed, it is not more expensive than the alternate formulation).</p>
<p>In this formulation, <code class="sourceCode cpp">std<span class="op">::</span>generator<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is definitely a <code class="sourceCode cpp">view</code> that does not violate any of the semantic requirements.</p>
<p>This formulation has another extremely significant consequence. <span class="citation" data-cites="N4128">[<a href="#ref-N4128" role="doc-biblioref">N4128</a>]</span> stated:</p>
<div class="quote">
<p>[Views] are lightweight objects that refer to elements they do not own. As a result, they can guarantee O(1) copyability and assignability.</p>
</div>
<p>But this would no longer <em>necessarily</em> have to be the case. Consider the following:</p>
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">template</span> <span class="op">&lt;</span>range R<span class="op">&gt;</span> <span class="kw">requires</span> is_object_v<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> movable<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="kw">class</span> owning_view <span class="op">:</span> <span class="kw">public</span> view_interface<span class="op">&lt;</span>owning_view<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3"></a>    R r_; <span class="co">// exposition only</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>    </span>
<span id="cb10-5"><a href="#cb10-5"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb10-6"><a href="#cb10-6"></a>    owning_view<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-7"><a href="#cb10-7"></a>    <span class="kw">constexpr</span> owning_view<span class="op">(</span>R<span class="op">&amp;&amp;</span> t<span class="op">)</span>;</span>
<span id="cb10-8"><a href="#cb10-8"></a>    </span>
<span id="cb10-9"><a href="#cb10-9"></a>    owning_view<span class="op">(</span><span class="kw">const</span> owning_view<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb10-10"><a href="#cb10-10"></a>    owning_view<span class="op">(</span>owning_view<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-11"><a href="#cb10-11"></a>    owning_view<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> owning_view<span class="op">&amp;)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb10-12"><a href="#cb10-12"></a>    owning_view<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>owning_view<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-13"><a href="#cb10-13"></a></span>
<span id="cb10-14"><a href="#cb10-14"></a>    <span class="kw">constexpr</span> R<span class="op">&amp;</span> base<span class="op">()</span> <span class="op">&amp;</span> <span class="op">{</span> <span class="cf">return</span> r_; <span class="op">}</span></span>
<span id="cb10-15"><a href="#cb10-15"></a>    <span class="kw">constexpr</span> <span class="kw">const</span> R<span class="op">&amp;</span> base<span class="op">()</span> <span class="kw">const</span><span class="op">&amp;</span> <span class="op">{</span> <span class="cf">return</span> r_; <span class="op">}</span></span>
<span id="cb10-16"><a href="#cb10-16"></a>    <span class="kw">constexpr</span> R<span class="op">&amp;&amp;</span> base<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-17"><a href="#cb10-17"></a>    <span class="kw">constexpr</span> <span class="kw">const</span> R<span class="op">&amp;&amp;</span> base<span class="op">()</span> <span class="kw">const</span><span class="op">&amp;&amp;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-18"><a href="#cb10-18"></a></span>
<span id="cb10-19"><a href="#cb10-19"></a>    <span class="kw">constexpr</span> iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> begin<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>begin<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-20"><a href="#cb10-20"></a>    <span class="kw">constexpr</span> iterator_t<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span> begin<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;{</span> <span class="cf">return</span> ranges<span class="op">::</span>begin<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-21"><a href="#cb10-21"></a>    </span>
<span id="cb10-22"><a href="#cb10-22"></a>    <span class="kw">constexpr</span> sentinel_t<span class="op">&lt;</span>R<span class="op">&gt;</span> end<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>end<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-23"><a href="#cb10-23"></a>    <span class="kw">constexpr</span> sentinel_t<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span> end<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>end<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb10-24"><a href="#cb10-24"></a></span>
<span id="cb10-25"><a href="#cb10-25"></a></span>
<span id="cb10-26"><a href="#cb10-26"></a>    <span class="co">// + overloads for empty, size, data</span></span>
<span id="cb10-27"><a href="#cb10-27"></a><span class="op">}</span>;</span>
<span id="cb10-28"><a href="#cb10-28"></a>  </span>
<span id="cb10-29"><a href="#cb10-29"></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="cb10-30"><a href="#cb10-30"></a>owning_view<span class="op">(</span>R<span class="op">&amp;&amp;)</span> <span class="op">-&gt;</span> owning_view<span class="op">&lt;</span>R<span class="op">&gt;</span>;</span></code></pre></div>
</blockquote>
<p>An <code class="sourceCode cpp">owning_view<span class="op">&lt;</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span></code> would completely satisfy the semantics of <code class="sourceCode cpp">view</code>: it is not copyable, it is O(1) movable, and moved-from object would be O(1) destructible. All without sacrificing any of the benefit that views provide: cheap construction of range adaptor pipelines.</p>
<p>Adopting these semantics, along with <code class="sourceCode cpp">owning_view</code>, would further allow us to respecify <code class="sourceCode cpp">views<span class="op">::</span>all</code> (<span>24.7.5
 <a href="https://wg21.link/range.all">[range.all]</a></span>) as:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> The name <code class="sourceCode cpp">views​<span class="op">::</span>​all</code> denotes a range adaptor object ([range.adaptor.object]). Given a subexpression <code class="sourceCode cpp">E</code>, the expression <code class="sourceCode cpp">views​<span class="op">::</span>​all<span class="op">(</span>E<span class="op">)</span></code> is expression-equivalent to:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> <code class="sourceCode cpp"><em>decay-copy</em><span class="op">(</span>E<span class="op">)</span></code> if the decayed type of <code class="sourceCode cpp">E</code> models <code class="sourceCode cpp">view</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> Otherwise, <code class="sourceCode cpp">ref_view<span class="op">{</span>E<span class="op">}</span></code> if that expression is well-formed.</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">subrange{E}</code></span></del></span> <span class="addu"><code class="sourceCode cpp">owning_view<span class="op">{</span>E<span class="op">}</span></code></span>.</li>
</ul>
</blockquote>
<p>The first sub-bullet effectively rejects using lvalue non-copyable views, as desired. Then the second bullet captures lvalue non-view ranges by reference and the new third bullet<a href="#fn3" class="footnote-ref" id="fnref3" role="doc-noteref"><sup>3</sup></a> would capture rvalue non-view ranges by ownership. This is safer and more ergonomic too.</p>
<p>Making the above change implies we also need to respecify <code class="sourceCode cpp">viewable_range</code> (in <span>24.4.5
 <a href="https://wg21.link/range.refinements">[range.refinements]</a></span>/5), since this concept and <code class="sourceCode cpp">views<span class="op">::</span>all</code> need to stay in sync:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</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 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;</span>
<span id="cb11-2"><a href="#cb11-2"></a>  concept viewable_range =</span>
<span id="cb11-3"><a href="#cb11-3"></a>    range&lt;T&gt; &amp;&amp;</span>
<span id="cb11-4"><a href="#cb11-4"></a>    ((view&lt;remove_cvref_t&lt;T&gt;&gt; &amp;&amp; constructible_from&lt;remove_cvref_t&lt;T&gt;, T&gt;) ||</span>
<span id="cb11-5"><a href="#cb11-5"></a>     (!view&lt;remove_cvref_t&lt;T&gt;&gt; &amp;&amp; <span class="rm" style="color: #bf0303"><del>borrowed_range<T></del></span> <span class="addu">(is_lvalue_reference_v&lt;T&gt; || movable&lt;remove_reference_t&lt;T&gt;&gt;)</span>));</span></code></pre></div>
</blockquote>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="what-is-a-view"><span class="header-section-number">5</span> What is a <code class="sourceCode cpp">view</code>?<a href="#what-is-a-view" class="self-link"></a></h1>
<p>Once upon a time, a <code class="sourceCode cpp">view</code> was a cheaply copyable, non-owning range. We’ve already somewhat lost the “cheaply copyable” requirement since views don’t have to be copyable, and now this paper is suggesting that we also lose the non-owning part.</p>
<p>So how do you answer the question now?</p>
<p>There may not be a clean answer, which is admittedly unsatisfying, but it mainly boils down to:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">auto</span> rng <span class="op">=</span> v <span class="op">|</span> views<span class="op">::</span>reverse;</span></code></pre></div>
</blockquote>
<p>If <code class="sourceCode cpp">v</code> is an lvalue, do you want <code class="sourceCode cpp">rng</code> to <em>copy</em> <code class="sourceCode cpp">v</code> or to <em>refer</em> to <code class="sourceCode cpp">v</code>? If you want it to copy <code class="sourceCode cpp">v</code>, because copying <code class="sourceCode cpp">v</code> is cheap and you want to avoid paying for indirection and potentional dangling, then <code class="sourceCode cpp">v</code> is a <code class="sourceCode cpp">view</code>. If you want to refer to <code class="sourceCode cpp">v</code>, because copying <code class="sourceCode cpp">v</code> is expensive (possibly more expensive than the algorithm you’re doing), then <code class="sourceCode cpp">v</code> is not a view. <code class="sourceCode cpp">string_view</code> is a <code class="sourceCode cpp">view</code>, <code class="sourceCode cpp">vector<span class="op">&lt;</span>string<span class="op">&gt;</span></code> is not.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="implementation-experience"><span class="header-section-number">6</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>This proposal has been implemented and passes the libstdc++ testsuite (with suitable modifications).</p>
<h1 data-number="7" style="border-bottom:1px solid #cccccc" id="proposed-wording"><span class="header-section-number">7</span> Proposed Wording<a href="#proposed-wording" class="self-link"></a></h1>
<p>This also resolves <span class="citation" data-cites="LWG3452">[<a href="#ref-LWG3452" role="doc-biblioref">LWG3452</a>]</span>.</p>
<p>Add <code class="sourceCode cpp">owning_view</code> to <span>24.2
 <a href="https://wg21.link/ranges.syn">[ranges.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1"></a>#include &lt;compare&gt;              // see [compare.syn]</span>
<span id="cb13-2"><a href="#cb13-2"></a>#include &lt;initializer_list&gt;     // see [initializer.list.syn]</span>
<span id="cb13-3"><a href="#cb13-3"></a>#include &lt;iterator&gt;             // see [iterator.synopsis]</span>
<span id="cb13-4"><a href="#cb13-4"></a></span>
<span id="cb13-5"><a href="#cb13-5"></a>namespace std::ranges {</span>
<span id="cb13-6"><a href="#cb13-6"></a>  // ...</span>
<span id="cb13-7"><a href="#cb13-7"></a>  </span>
<span id="cb13-8"><a href="#cb13-8"></a>  // [range.all], all view</span>
<span id="cb13-9"><a href="#cb13-9"></a>  namespace views {</span>
<span id="cb13-10"><a href="#cb13-10"></a>    inline constexpr <em>unspecified</em> all = <em>unspecified</em>;</span>
<span id="cb13-11"><a href="#cb13-11"></a></span>
<span id="cb13-12"><a href="#cb13-12"></a>    template&lt;viewable_range R&gt;</span>
<span id="cb13-13"><a href="#cb13-13"></a>      using all_t = decltype(all(declval&lt;R&gt;()));</span>
<span id="cb13-14"><a href="#cb13-14"></a>  }</span>
<span id="cb13-15"><a href="#cb13-15"></a></span>
<span id="cb13-16"><a href="#cb13-16"></a>  template&lt;range R&gt;</span>
<span id="cb13-17"><a href="#cb13-17"></a>    requires is_object_v&lt;R&gt;</span>
<span id="cb13-18"><a href="#cb13-18"></a>  class ref_view;</span>
<span id="cb13-19"><a href="#cb13-19"></a></span>
<span id="cb13-20"><a href="#cb13-20"></a>  template&lt;class T&gt;</span>
<span id="cb13-21"><a href="#cb13-21"></a>    inline constexpr bool enable_borrowed_range&lt;ref_view&lt;T&gt;&gt; = true;</span>
<span id="cb13-22"><a href="#cb13-22"></a></span>
<span id="cb13-23"><a href="#cb13-23"></a><span class="va">+ template&lt;range R&gt;</span></span>
<span id="cb13-24"><a href="#cb13-24"></a><span class="va">+   requires <em>see below</em></span></span>
<span id="cb13-25"><a href="#cb13-25"></a><span class="va">+ class owning_view;</span></span>
<span id="cb13-26"><a href="#cb13-26"></a><span class="va">+ </span></span>
<span id="cb13-27"><a href="#cb13-27"></a><span class="va">+ template&lt;class T&gt;</span></span>
<span id="cb13-28"><a href="#cb13-28"></a><span class="va">+   inline constexpr bool enable_borrowed_range&lt;owning_view&lt;T&gt;&gt; = enable_borrowed_range&lt;T&gt;;  </span></span>
<span id="cb13-29"><a href="#cb13-29"></a></span>
<span id="cb13-30"><a href="#cb13-30"></a>  // ...    </span>
<span id="cb13-31"><a href="#cb13-31"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Relax the requirements on <code class="sourceCode cpp">view</code> in <span>24.4.4
 <a href="https://wg21.link/range.view">[range.view]</a></span>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The <code class="sourceCode cpp">view</code> concept specifies the requirements of a <code class="sourceCode cpp">range</code> type that has <span class="rm" style="color: #bf0303"><del>constant time move construction, move assignment, and destruction; that is, the cost of these operations is independent of the number of elements in the <span><code class="sourceCode default">view</code></span></del></span> <span class="addu">semantic properties that make it suitable for use in constructing range adaptor pipelines</span>.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2"></a>  <span class="kw">concept</span> view <span class="op">=</span></span>
<span id="cb14-3"><a href="#cb14-3"></a>    range<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> movable<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> enable_view<span class="op">&lt;</span>T<span class="op">&gt;</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> <code class="sourceCode cpp">T</code> models <code class="sourceCode cpp">view</code> only if:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> <code class="sourceCode cpp">T</code> has <code class="sourceCode cpp">O<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code> move construction; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span> has <span><code class="sourceCode default">O(1)</code></span> move assignment</del></span> <span class="addu">move assignment of an object of type <code class="sourceCode cpp">T</code> is no more complex than destruction followed by move construction</span>; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span> has <span><code class="sourceCode default">O(1)</code></span> destruction</del></span> <span class="addu">if <code class="sourceCode cpp">N</code> copies and/or moves are made from an object of type <code class="sourceCode cpp">T</code> that contained <code class="sourceCode cpp">M</code> elements, then those <code class="sourceCode cpp">N</code> objects have <code class="sourceCode cpp">O<span class="op">(</span>N<span class="op">+</span>M<span class="op">)</span></code> destruction [<em>Note</em>: this implies that a moved-from object of type <code class="sourceCode cpp">T</code> has <code class="sourceCode cpp">O<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code> destruction -<em>end note</em>]</span>; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span> <code class="sourceCode cpp">copy_constructible<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, or <code class="sourceCode cpp">T</code> has <code class="sourceCode cpp">O<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code> copy construction; and</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span> <code class="sourceCode cpp">copyable<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, or <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">T</code></span> has <span><code class="sourceCode default">O(1)</code></span> copy assignment</del></span> <span class="addu">copy assignment of an object of type <code class="sourceCode cpp">T</code> is no more complex than destruction followed by copy construction</span>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span> [<em>Example 1</em>: Examples of <code class="sourceCode cpp">view</code>s are:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> A range type that wraps a pair of iterators.</li>
<li><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> A range type that holds its elements by <code class="sourceCode cpp">shared_ptr</code> and shares ownership with all its copies.</li>
<li><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span> A range type that generates its elements on demand.</li>
</ul>
<p>Most containers are not views since <span class="rm" style="color: #bf0303"><del>destruction of</del></span> <span class="addu">copying</span> the container <span class="rm" style="color: #bf0303"><del>destroys</del></span> <span class="addu">copies all of</span> the elements, which cannot be done in constant time. — <em>end example</em>]</p>
</blockquote>
<p>Change the definition of <code class="sourceCode cpp">viewable_range</code> to line up with <code class="sourceCode cpp">views<span class="op">::</span>all</code> (see later) in <span>24.4.5
 <a href="https://wg21.link/range.refinements">[range.refinements]</a></span>, inserting the new exposition-only variable template <code class="sourceCode cpp"><em>is-initializer-list</em><span class="op">&lt;</span>T<span class="op">&gt;</span></code> <span class="ednote" style="color: #0000ff">[ Editor&#39;s note: <code class="sourceCode default">remove_reference_t</code> rather than <code class="sourceCode default">remove_cvref_t</code> because we need to reject <code class="sourceCode default">const vector&lt;int&gt;&amp;&amp;</code> from being a <code class="sourceCode default">viewable_range</code> ]</span>:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb15"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb15-1"><a href="#cb15-1"></a>template &lt;class R&gt;</span>
<span id="cb15-2"><a href="#cb15-2"></a>  inline constexpr bool <em>is-initializer-list</em> = <em>see below</em>; // exposition only</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">*</a></span> For a type <code class="sourceCode cpp">R</code>, <code class="sourceCode cpp"><em>is-initializer-list</em><span class="op">&lt;</span>R<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code> if and only if <code class="sourceCode cpp">remove_cvref_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is a specialization of <code class="sourceCode cpp">std<span class="op">::</span>initializer_list</code>.</p>
</div>
<p><span class="marginalizedparent"><a class="marginalized">5</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 class="sourceCode" id="cb16"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1"></a>template&lt;class T&gt;</span>
<span id="cb16-2"><a href="#cb16-2"></a>concept viewable_range =</span>
<span id="cb16-3"><a href="#cb16-3"></a>  range&lt;T&gt; &amp;&amp;</span>
<span id="cb16-4"><a href="#cb16-4"></a>  ((view&lt;remove_cvref_t&lt;T&gt;&gt; &amp;&amp; constructible_from&lt;remove_cvref_t&lt;T&gt;, T&gt;) ||</span>
<span id="cb16-5"><a href="#cb16-5"></a>   (!view&lt;remove_cvref_t&lt;T&gt;&gt; &amp;&amp; <span class="rm" style="color: #bf0303"><del>borrowed_range&lt;T&gt;</del></span></span>
<span id="cb16-6"><a href="#cb16-6"></a>         <span class="addu">(is_lvalue_reference_v&lt;T&gt; || (movable&lt;remove_reference_t&lt;T&gt;&gt; &amp;&amp; !<em>is-initializer-list</em>&lt;T&gt;))</span>));</span></code></pre></div>
</blockquote>
<p>Change the last bullet in the definition of <code class="sourceCode cpp">views<span class="op">::</span>all</code> in <span>24.7.5.1
 <a href="https://wg21.link/range.all.general">[range.all.general]</a></span>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> The name <code class="sourceCode cpp">views​<span class="op">::</span>​all</code> denotes a range adaptor object ([range.adaptor.object]). Given a subexpression <code class="sourceCode cpp">E</code>, the expression <code class="sourceCode cpp">views​<span class="op">::</span>​all<span class="op">(</span>E<span class="op">)</span></code> is expression-equivalent to:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> <code class="sourceCode cpp"><em>decay-copy</em><span class="op">(</span>E<span class="op">)</span></code> if the decayed type of <code class="sourceCode cpp">E</code> models <code class="sourceCode cpp">view</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> Otherwise, <code class="sourceCode cpp">ref_view<span class="op">{</span>E<span class="op">}</span></code> if that expression is well-formed.</li>
<li><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">subrange{E}</code></span></del></span> <span class="addu"><code class="sourceCode cpp">owning_view<span class="op">{</span>E<span class="op">}</span></code></span>.</li>
</ul>
</blockquote>
<p>Add a new subclause under [range.all] directly after <span>24.7.5.2
 <a href="https://wg21.link/range.ref.view">[range.ref.view]</a></span> named “Class template <code class="sourceCode cpp">owning_view</code>” with stable name [range.owning.view]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> <code class="sourceCode cpp">owning_view</code> is a move-only <code class="sourceCode cpp">view</code> of the elements of some other <code class="sourceCode cpp">range</code>.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a><span class="kw">namespace</span> std<span class="op">::</span>ranges <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2"></a>  <span class="kw">template</span><span class="op">&lt;</span>range R<span class="op">&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3"></a>    <span class="kw">requires</span> movable<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">(!</span><em>is-initializer-list</em><span class="op">&lt;</span>R<span class="op">&gt;)</span> <span class="co">// see [range.refinements]</span></span>
<span id="cb17-4"><a href="#cb17-4"></a>  <span class="kw">class</span> owning_view <span class="op">:</span> <span class="kw">public</span> view_interface<span class="op">&lt;</span>owning_view<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb17-5"><a href="#cb17-5"></a>  <span class="kw">private</span><span class="op">:</span></span>
<span id="cb17-6"><a href="#cb17-6"></a>    R r_ <span class="op">=</span> R<span class="op">()</span>;   <span class="co">// exposition only</span></span>
<span id="cb17-7"><a href="#cb17-7"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb17-8"><a href="#cb17-8"></a>    owning_view<span class="op">()</span> <span class="kw">requires</span> default_initializable<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb17-9"><a href="#cb17-9"></a>    <span class="kw">constexpr</span> owning_view<span class="op">(</span>R<span class="op">&amp;&amp;</span> t<span class="op">)</span>;</span>
<span id="cb17-10"><a href="#cb17-10"></a></span>
<span id="cb17-11"><a href="#cb17-11"></a>    owning_view<span class="op">(</span>owning_view<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb17-12"><a href="#cb17-12"></a>    owning_view<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span>owning_view<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb17-13"><a href="#cb17-13"></a></span>
<span id="cb17-14"><a href="#cb17-14"></a>    <span class="kw">constexpr</span> R<span class="op">&amp;</span> base<span class="op">()</span> <span class="op">&amp;</span> <span class="op">{</span> <span class="cf">return</span> r_; <span class="op">}</span></span>
<span id="cb17-15"><a href="#cb17-15"></a>    <span class="kw">constexpr</span> <span class="kw">const</span> R<span class="op">&amp;</span> base<span class="op">()</span> <span class="kw">const</span><span class="op">&amp;</span> <span class="op">{</span> <span class="cf">return</span> r_; <span class="op">}</span></span>
<span id="cb17-16"><a href="#cb17-16"></a>    <span class="kw">constexpr</span> R<span class="op">&amp;&amp;</span> base<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-17"><a href="#cb17-17"></a>    <span class="kw">constexpr</span> <span class="kw">const</span> R<span class="op">&amp;&amp;</span> base<span class="op">()</span> <span class="kw">const</span><span class="op">&amp;&amp;</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-18"><a href="#cb17-18"></a></span>
<span id="cb17-19"><a href="#cb17-19"></a>    <span class="kw">constexpr</span> iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> begin<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>begin<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-20"><a href="#cb17-20"></a>    <span class="kw">constexpr</span> sentinel_t<span class="op">&lt;</span>R<span class="op">&gt;</span> end<span class="op">()</span> <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>end<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-21"><a href="#cb17-21"></a>    </span>
<span id="cb17-22"><a href="#cb17-22"></a>    <span class="kw">constexpr</span> iterator_t<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span> begin<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span></span>
<span id="cb17-23"><a href="#cb17-23"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>begin<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-24"><a href="#cb17-24"></a>    <span class="kw">constexpr</span> sentinel_t<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span> end<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span></span>
<span id="cb17-25"><a href="#cb17-25"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>end<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-26"><a href="#cb17-26"></a></span>
<span id="cb17-27"><a href="#cb17-27"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> empty<span class="op">()</span></span>
<span id="cb17-28"><a href="#cb17-28"></a>      <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> ranges<span class="op">::</span>empty<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-29"><a href="#cb17-29"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>empty<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span>    </span>
<span id="cb17-30"><a href="#cb17-30"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> empty<span class="op">()</span> <span class="kw">const</span></span>
<span id="cb17-31"><a href="#cb17-31"></a>      <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> ranges<span class="op">::</span>empty<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-32"><a href="#cb17-32"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>empty<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-33"><a href="#cb17-33"></a></span>
<span id="cb17-34"><a href="#cb17-34"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">requires</span> sized_range<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb17-35"><a href="#cb17-35"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>size<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-36"><a href="#cb17-36"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> size<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> sized_range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span></span>
<span id="cb17-37"><a href="#cb17-37"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>size<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-38"><a href="#cb17-38"></a></span>
<span id="cb17-39"><a href="#cb17-39"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="kw">requires</span> contiguous_range<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb17-40"><a href="#cb17-40"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>data<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-41"><a href="#cb17-41"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span> contiguous_range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span></span>
<span id="cb17-42"><a href="#cb17-42"></a>    <span class="op">{</span> <span class="cf">return</span> ranges<span class="op">::</span>data<span class="op">(</span>r_<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb17-43"><a href="#cb17-43"></a>  <span class="op">}</span>;</span>
<span id="cb17-44"><a href="#cb17-44"></a><span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="kw">constexpr</span> owning_view<span class="op">(</span>R<span class="op">&amp;&amp;</span> t<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> <em>Effects</em>: Initializes <code class="sourceCode cpp">r_</code> with <code class="sourceCode cpp">std<span class="op">::</span>move<span class="op">(</span>t<span class="op">)</span></code>.</p>
</blockquote>
<h1 data-number="8" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">8</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-LWG3452">
<p>[LWG3452] Mathias Stearn. Are views really supposed to have strict 𝒪(1) destruction? <br />
<a href="https://wg21.link/lwg3452">https://wg21.link/lwg3452</a></p>
</div>
<div id="ref-N4128">
<p>[N4128] E. Niebler, S. Parent, A. Sutton. 2014-10-10. Ranges for the Standard Library, Revision 1. <br />
<a href="https://wg21.link/n4128">https://wg21.link/n4128</a></p>
</div>
<div id="ref-P1456R1">
<p>[P1456R1] Casey Carter. 2019-11-12. Move-only views. <br />
<a href="https://wg21.link/p1456r1">https://wg21.link/p1456r1</a></p>
</div>
<div id="ref-P2168R3">
<p>[P2168R3] Corentin Jabot, Lewis Baker. 2021-04-19. generator: A Synchronous Coroutine Generator Compatible With Ranges. <br />
<a href="https://wg21.link/p2168r3">https://wg21.link/p2168r3</a></p>
</div>
<div id="ref-P2325R3">
<p>[P2325R3] Barry Revzin. 2021-05-14. Views should not be required to be default constructible. <br />
<a href="https://wg21.link/p2325r3">https://wg21.link/p2325r3</a></p>
</div>
<div id="ref-P2415R0">
<p>[P2415R0] Barry Revzin, Tim Song. 2021-07-15. What is a view? <br />
<a href="https://wg21.link/p2415r0">https://wg21.link/p2415r0</a></p>
</div>
</div>
<section class="footnotes" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>This is why they’re called <em>range</em> adaptors rather than <em>view</em> adaptors, perhaps that should change as well?<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn2" role="doc-endnote"><p>except <code class="sourceCode cpp">views<span class="op">::</span>single</code><a href="#fnref2" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
<li id="fn3" role="doc-endnote"><p>the existing third bullet could only have been hit by rvalue, <em>borrowed</em>, non-view ranges. Before the adoption of <span class="citation" data-cites="P2325R3">[<a href="#ref-P2325R3" role="doc-biblioref">P2325R3</a>]</span>, fixed-extent <code class="sourceCode cpp">span</code> was the pub quiz trivia answer to what this bullet was for. Afterwards, is there a real type that would fit here?<a href="#fnref3" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
