<!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-05-06" />
  <title>join_view should join all views of ranges</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, div.add blockquote { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
blockquote { background-color: #f6f8fa; }
</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"><code class="sourceCode cpp">join_view</code> should join all views of ranges</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2328R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-05-06</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>
      LWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      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="#abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#revision-history"><span class="toc-section-number">2</span> Revision history<span></span></a></li>
<li><a href="#motivation"><span class="toc-section-number">3</span> Motivation<span></span></a></li>
<li><a href="#design"><span class="toc-section-number">4</span> Design<span></span></a>
<ul>
<li><a href="#but-views-require-o1-operations"><span class="toc-section-number">4.1</span> But views require O(1) operations?<span></span></a></li>
<li><a href="#why-does-non-propagating-cache-clear-itself-when-it-is-moved-from"><span class="toc-section-number">4.2</span> Why does <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> clear itself when it is moved from?<span></span></a></li>
<li><a href="#is-this-a-breaking-change"><span class="toc-section-number">4.3</span> Is this a breaking change?<span></span></a></li>
</ul></li>
<li><a href="#wording"><span class="toc-section-number">5</span> Wording<span></span></a></li>
<li><a href="#bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes relaxing the constraint on <code class="sourceCode cpp">join_view</code> to support joining ranges of prvalue non-view ranges.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">2</span> Revision history<a href="#revision-history" class="self-link"></a></h1>
<ul>
<li>R1: Incorporate LWG review feedback. Add a missing <code class="sourceCode cpp"><span class="kw">constexpr</span></code> to <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache<span class="op">::</span>emplace<span class="op">-</span>deref</code></em>. Cross-reference <span class="citation" data-cites="P2231R1">[<a href="#ref-P2231R1" role="doc-biblioref">P2231R1</a>]</span>.</li>
</ul>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Currently, <code class="sourceCode cpp">join_view</code> supports joining</p>
<ul>
<li>a range of glvalue ranges (whether or not the inner ranges are views), or</li>
<li>a range of prvalue views.</li>
</ul>
<p>Notably missing from the list is support for joining prvalue non-view ranges. As noted in <span class="citation" data-cites="P2214R0">[<a href="#ref-P2214R0" role="doc-biblioref">P2214R0</a>]</span> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2214r0.html#flat_map">§ 3.4.1</a>, this is a fairly common use case. P2214R0 proposes to solve this problem by introducing a <code class="sourceCode cpp">views<span class="op">::</span>cache_latest</code> adaptor, based on <code class="sourceCode cpp">views<span class="op">::</span>cache1</code> from range-v3, that would cache the result of dereferencing the source iterator and produce it as a glvalue, so that the user can write <code class="sourceCode cpp">r <span class="op">|</span> transform<span class="op">(</span>function_returning_vector<span class="op">)</span> <span class="op">|</span> cache_latest <span class="op">|</span> join</code>; it also proposes a new adaptor, commonly called <code class="sourceCode cpp">flat_map</code> in other languages, that would automatically add <code class="sourceCode cpp">cache_latest</code> to the pipeline when needed.</p>
<p>This solution has the appeal of generality but runs into one problem with <code class="sourceCode cpp">cache_latest</code>: its iterator’s <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">*()</span> <span class="kw">const</span></code> - a const-qualified member function as required by <code class="sourceCode cpp">indirectly_readable</code> - can mutate the cache, and so concurrent calls to it from different threads can result in a data race. This violates <span>16.4.6.10 <a href="https://wg21.link/res.on.data.races">[res.on.data.races]</a></span>. Given that <code class="sourceCode cpp">cache_latest</code> is always an input-only range, and can be given move-only iterators, this might not be a major problem; or perhaps <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">++</span></code> can be made to update the cache instead, with the cost of potentially unnecessary cache updates as the range is traversed if the user doesn’t need to access every element. This open design issue calls into question the suitability of <code class="sourceCode cpp">cache_latest</code> for standardization during the C++23 time frame.</p>
<p>Moreover, <code class="sourceCode cpp">cache_latest</code> is not exactly easy to understand or discover - there’s no hint that you need to use it; you just have to know of its existence, figure out why your <code class="sourceCode cpp">join</code> doesn’t compile, and then recognize that <code class="sourceCode cpp">cache_latest</code> can solve the problem. The <code class="sourceCode cpp">join_view</code> restriction has also been a recurring source of confusion and frustration (if #ranges on the cpplang slack is any indication). By making it Just Work, we also obviate the need for a separate commonly-known-as-<code class="sourceCode cpp">flat_map</code> adaptor. <code class="sourceCode cpp">cache_latest</code> certainly has other uses beyond <code class="sourceCode cpp">join</code>, but those are more in the “improved performance” category than the “new functionality” category, and falls outside the Tier 1 criteria as described in P2214R0. It may be proposed for a later standard.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="design"><span class="header-section-number">4</span> Design<a href="#design" class="self-link"></a></h1>
<p>When dealing with a range of prvalue views, <code class="sourceCode cpp">join_view</code> produces input iterators, and stores a copy of the view it is currently iterating over inside the <code class="sourceCode cpp">join_view</code>. This paper proposes that we make it do basically the same thing with ranges of prvalue ranges; the only difference is that instead of holding the view directly, it holds the range inside a <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> (which is the kebab-cased name of the class template range-v3 uses to implement <code class="sourceCode cpp">cache1</code>).</p>
<p>A <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache<span class="op">&lt;</span>T<span class="op">&gt;</span></code></em> is like an <code class="sourceCode cpp">optional<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, except that it doesn’t propagate: attempts to copy or move it produces an empty cache instead. This ensures that <code class="sourceCode cpp">join_view</code>’s copy or move doesn’t depend on what the underlying view produces. The wording below is crafted to guarantee that any prvalue range produced by <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">*</span></code> is constructed directly into the cache and will not be copied or moved.</p>
<h2 data-number="4.1" id="but-views-require-o1-operations"><span class="header-section-number">4.1</span> But views require O(1) operations?<a href="#but-views-require-o1-operations" class="self-link"></a></h2>
<p>At any time prior to the call to <code class="sourceCode cpp">begin</code>, a <code class="sourceCode cpp">join_view</code> can be still be copied (if the underlying view can) and moved, and operations are in constant time because the cache is empty.</p>
<p>Since <code class="sourceCode cpp">join_view</code> in this case is an input range, <code class="sourceCode cpp">begin</code> can only be called once. After <code class="sourceCode cpp">begin</code> is called, the <code class="sourceCode cpp">join_view</code> object can no longer be used as a range, let alone a view, so the fact that destroying or moving from it may require destruction of the cached elements is irrelevant.</p>
<h2 data-number="4.2" id="why-does-non-propagating-cache-clear-itself-when-it-is-moved-from"><span class="header-section-number">4.2</span> Why does <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> clear itself when it is moved from?<a href="#why-does-non-propagating-cache-clear-itself-when-it-is-moved-from" class="self-link"></a></h2>
<p>As a general matter, the use case for <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> is to cache something that came from another thing <em>X</em> where <em>X</em> and the cache are typically data members side-by-side. Moving from <em>X</em> usually means that the contents of the cache is no longer meaningful and should be invalidated. (In particular, the various views that need to cache <code class="sourceCode cpp">begin<span class="op">()</span></code> in range-v3 use <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> for this purpose.)</p>
<p>In <code class="sourceCode cpp">join_view</code>’s case, it’s also a serious error to move from something that is being iterated over, so clearing the cache may help catching such errors early.</p>
<h2 data-number="4.3" id="is-this-a-breaking-change"><span class="header-section-number">4.3</span> Is this a breaking change?<a href="#is-this-a-breaking-change" class="self-link"></a></h2>
<p>This proposal does not have to be a breaking change if we retain the existing behavior for ranges of prvalue views. However, the wording below applies the <em><code class="sourceCode cpp">non<span class="op">-</span>propagating<span class="op">-</span>cache</code></em> change unconditionally, so it changes observable behavior relative to C++20 as published in two ways:</p>
<ol type="1">
<li><code class="sourceCode cpp">join_view</code> no longer default constructs the cached view when constructed;</li>
<li><code class="sourceCode cpp">join_view</code> iterator increments no longer assigns to the inner view but destroys any previous view and emplaces in place instead.</li>
</ol>
<p>Both changes appear to be desirable. The first means that we don’t pay the cost of default constructing an inner view when the resulting view will just be overwritten later. It also avoids tying <code class="sourceCode cpp">join_view</code>’s copyability with that of the cached view when the latter is an implementation detail.</p>
<p>The second change means that instead of move assignment to the existing view followed by destruction of a temporary, we destroy the existing view and constructs the return value of <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">*</span></code> directly into its place. This is potentially more efficient.</p>
<p>This paper recommends that the proposed changes, or at least those changes that modify the handling of ranges of prvalue views, be applied retroactively to C++20 to simplify both specification and implementation. The use of <code class="sourceCode cpp">join_view</code> in the wild is likely rare because it is only shipped by libstdc++ as of the writing of R0 of this paper, and only as experimental.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="wording"><span class="header-section-number">5</span> Wording<a href="#wording" class="self-link"></a></h1>
<div>
<ol type="1">
<li>Edit <span>24.2 <a href="https://wg21.link/ranges.syn">[ranges.syn]</a></span>, header <code class="sourceCode cpp"><span class="op">&lt;</span>ranges<span class="op">&gt;</span></code> synopsis, as indicated:</li>
</ol>
<blockquote>
<div>
<div class="sourceCode" id="cb1"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb1-1"><a href="#cb1-1"></a> [...]</span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a> namespace std::ranges {</span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a>   [...]</span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a>   // [range.join], join view</span>
<span id="cb1-8"><a href="#cb1-8"></a>   template&lt;input_range V&gt;</span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="st">-    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt; <span class="diffdel">&amp;&amp;</span></span></span>
<span id="cb1-10"><a href="#cb1-10"></a><span class="va">+    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;</span></span>
<span id="cb1-11"><a href="#cb1-11"></a><span class="st">-             (is_reference_v&lt;range_reference_t&lt;V&gt;&gt; ||</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="st">-              view&lt;range_value_t&lt;V&gt;&gt;)</span></span>
<span id="cb1-13"><a href="#cb1-13"></a>   class join_view;</span>
<span id="cb1-14"><a href="#cb1-14"></a></span>
<span id="cb1-15"><a href="#cb1-15"></a>   [...]</span>
<span id="cb1-16"><a href="#cb1-16"></a> }</span></code></pre></div>
</div>
</blockquote>
<ol start="2" type="1">
<li>Add the following subclause under <span>24.7 <a href="https://wg21.link/range.adaptors">[range.adaptors]</a></span>, immediately after <span>24.7.3 <a href="https://wg21.link/range.semi.wrap">[range.semi.wrap]</a></span>:</li>
</ol>
<blockquote>
<p><span class="ednote" style="color: #0000ff">[ Editor&#39;s note: The <code class="sourceCode default">constexpr</code> in the specification of the member functions of <em><code class="sourceCode default">non-propagating-cache</code></em> (other than the copy constructor) assumes the application of <span class="citation" data-cites="P2231R1">[<a href="#ref-P2231R1" role="doc-biblioref">P2231R1</a>]</span>. ]</span></p>
<div class="add" style="color: #006e28">

<h3 id="non-propagating-cache-range.nonprop.cache" class="unnumbered">24.7.? Non-propagating cache [range.nonprop.cache]<a href="#non-propagating-cache-range.nonprop.cache" class="self-link"></a></h3>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> Some types in this subclause are specified in terms of an exposition-only class template <em><code class="sourceCode default">non-propagating-cache</code></em>. <code class="sourceCode default"><em>non-propagating-cache</em>&lt;T&gt;</code> behaves exactly like <code class="sourceCode default">optional&lt;T&gt;</code> with the following differences:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <code class="sourceCode default"><em>non-propagating-cache</em>&lt;T&gt;</code> constrains its type parameter <code class="sourceCode default">T</code> with <code class="sourceCode default">is_object_v&lt;T&gt;</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> The copy constructor is equivalent to:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1"></a>    constexpr <em>non-propagating-cache</em>(const <em>non-propagating-cache</em>&amp;) noexcept { }</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> The move constructor is equivalent to:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1"></a>    constexpr <em>non-propagating-cache</em>(<em>non-propagating-cache</em>&amp;&amp; other) noexcept</span>
<span id="cb3-2"><a href="#cb3-2"></a>    {</span>
<span id="cb3-3"><a href="#cb3-3"></a>      other.reset();</span>
<span id="cb3-4"><a href="#cb3-4"></a>    }</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> The copy assignment operator is equivalent to:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1"></a>    constexpr <em>non-propagating-cache</em>&amp; operator=(const <em>non-propagating-cache</em>&amp; other) noexcept</span>
<span id="cb4-2"><a href="#cb4-2"></a>    {</span>
<span id="cb4-3"><a href="#cb4-3"></a>      if (addressof(other) != this)</span>
<span id="cb4-4"><a href="#cb4-4"></a>        reset();</span>
<span id="cb4-5"><a href="#cb4-5"></a>      return *this;</span>
<span id="cb4-6"><a href="#cb4-6"></a>    }</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.5)</a></span> The move assignment operator is equivalent to:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb5-1"><a href="#cb5-1"></a>    constexpr <em>non-propagating-cache</em>&amp; operator=(<em>non-propagating-cache</em>&amp;&amp; other) noexcept</span>
<span id="cb5-2"><a href="#cb5-2"></a>    {</span>
<span id="cb5-3"><a href="#cb5-3"></a>      reset();</span>
<span id="cb5-4"><a href="#cb5-4"></a>      other.reset();</span>
<span id="cb5-5"><a href="#cb5-5"></a>      return *this;</span>
<span id="cb5-6"><a href="#cb5-6"></a>    }</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.6)</a></span> <code class="sourceCode default"><em>non-propagating-cache</em>&lt;T&gt;</code> has an additional member function template specified as follows:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1"></a>template&lt;class I&gt;</span>
<span id="cb6-2"><a href="#cb6-2"></a>constexpr T&amp; <em>emplace-deref</em>(const I&amp; i);    // exposition only</span></code></pre></div>
<blockquote>
<p><em>Mandates:</em> The declaration <code class="sourceCode default">T t(*i);</code> is well-formed for some invented variable <code class="sourceCode default">t</code>.</p>
<p><em>Effects:</em> Calls <code class="sourceCode default">reset()</code>. Then initializes the contained value as if direct-non-list-initializing an object of type <code class="sourceCode default">T</code> with the argument <code class="sourceCode default">*i</code>.</p>
<p><em>Postconditions:</em> <code class="sourceCode default">*this</code> contains a value.</p>
<p><em>Returns:</em> A reference to the new contained value.</p>
<p><em>Throws:</em> Any exception thrown by the initialization of the contained value.</p>
<p><em>Remarks:</em> If an exception is thrown during the initialization of <code class="sourceCode default">T</code>, <code class="sourceCode default">*this</code> does not contain a value, and the previous value (if any) has been destroyed.</p>
</blockquote></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> <span class="note1"><span>[ <em>Note 1:</em> </span><em><code class="sourceCode default">non-propagating-cache</code></em> enables an input view to temporarily cache values as it is iterated over.<span> — <em>end note</em> ]</span></span></p>
</div>
</blockquote>
<ol start="3" type="1">
<li>Modify <span>24.7.11.2 <a href="https://wg21.link/range.join.view">[range.join.view]</a></span> as indicated:</li>
</ol>
<blockquote>
<div>
<div class="sourceCode" id="cb7"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1"></a> namespace std::ranges {</span>
<span id="cb7-2"><a href="#cb7-2"></a>   template&lt;input_range V&gt;</span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="st">-    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt; <span class="diffdel">&amp;&amp;</span></span></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="va">+    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;</span></span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="st">-             (is_reference_v&lt;range_reference_t&lt;V&gt;&gt; ||</span></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="st">-              view&lt;range_value_t&lt;V&gt;&gt;)</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>   class join_view : public view_interface&lt;join_view&lt;V&gt;&gt; {</span>
<span id="cb7-8"><a href="#cb7-8"></a>   private:</span>
<span id="cb7-9"><a href="#cb7-9"></a>     using <em>InnerRng</em> =                    // exposition only</span>
<span id="cb7-10"><a href="#cb7-10"></a>       range_reference_t&lt;V&gt;;</span>
<span id="cb7-11"><a href="#cb7-11"></a>     // [range.join.iterator], class template join_view::iterator</span>
<span id="cb7-12"><a href="#cb7-12"></a>     template&lt;bool Const&gt;</span>
<span id="cb7-13"><a href="#cb7-13"></a>       struct <em>iterator</em>;                  // exposition only</span>
<span id="cb7-14"><a href="#cb7-14"></a>     // [range.join.sentinel], class template join_view::sentinel</span>
<span id="cb7-15"><a href="#cb7-15"></a>     template&lt;bool Const&gt;</span>
<span id="cb7-16"><a href="#cb7-16"></a>       struct <em>sentinel</em>;                  // exposition only</span>
<span id="cb7-17"><a href="#cb7-17"></a></span>
<span id="cb7-18"><a href="#cb7-18"></a>     V <em>base_</em> = V();                      // exposition only</span>
<span id="cb7-19"><a href="#cb7-19"></a><span class="st">-    views::all_t&lt;<em>InnerRng</em>&gt; <em>inner_</em> =     // exposition only, present only when !is_reference_v&lt;<em>InnerRng</em>&gt;</span></span>
<span id="cb7-20"><a href="#cb7-20"></a><span class="st">-      views::all_t&lt;<em>InnerRng</em>&gt;();</span></span>
<span id="cb7-21"><a href="#cb7-21"></a><span class="va">+    <em>non-propagating-cache</em>&lt;remove_cv_t&lt;<em>InnerRng</em>&gt;&gt; <em>inner_</em>;  // exposition only, present only when !is_reference_v&lt;<em>InnerRng</em>&gt;</span></span>
<span id="cb7-22"><a href="#cb7-22"></a>   public:</span>
<span id="cb7-23"><a href="#cb7-23"></a>     join_view() = default;</span>
<span id="cb7-24"><a href="#cb7-24"></a>     constexpr explicit join_view(V base);</span>
<span id="cb7-25"><a href="#cb7-25"></a></span>
<span id="cb7-26"><a href="#cb7-26"></a>     constexpr V base() const&amp; requires copy_constructible&lt;V&gt; { return base_; }</span>
<span id="cb7-27"><a href="#cb7-27"></a>     constexpr V base() &amp;&amp; { return std::move(base_); }</span>
<span id="cb7-28"><a href="#cb7-28"></a></span>
<span id="cb7-29"><a href="#cb7-29"></a>     [...]</span>
<span id="cb7-30"><a href="#cb7-30"></a>   };</span>
<span id="cb7-31"><a href="#cb7-31"></a></span>
<span id="cb7-32"><a href="#cb7-32"></a>   [...]</span>
<span id="cb7-33"><a href="#cb7-33"></a> }</span></code></pre></div>
</div>
</blockquote>
<ol start="4" type="1">
<li>Modify <span>24.7.11.3 <a href="https://wg21.link/range.join.iterator">[range.join.iterator]</a></span> as indicated:</li>
</ol>
<blockquote>
<div>
<div class="sourceCode" id="cb8"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1"></a>namespace std::ranges {</span>
<span id="cb8-2"><a href="#cb8-2"></a>  template&lt;input_range V&gt;</span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="st">-    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt; <span class="diffdel">&amp;&amp;</span></span></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="va">+    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="st">-             (is_reference_v&lt;range_reference_t&lt;V&gt;&gt; ||</span></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="st">-              view&lt;range_value_t&lt;V&gt;&gt;)</span></span>
<span id="cb8-7"><a href="#cb8-7"></a>  template&lt;bool Const&gt;</span>
<span id="cb8-8"><a href="#cb8-8"></a>  struct join_view&lt;V&gt;::<em>iterator</em> {</span>
<span id="cb8-9"><a href="#cb8-9"></a>    [...]</span>
<span id="cb8-10"><a href="#cb8-10"></a>  };</span>
<span id="cb8-11"><a href="#cb8-11"></a>}</span></code></pre></div>
</div>
<p>[…]</p>
<div>
<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">constexpr</span> <span class="dt">void</span> <em>satisfy</em><span class="op">()</span>;       <span class="co">// exposition only</span></span></code></pre></div>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span> <em>Effects:</em> Equivalent to:</p>
<div class="rm" style="color: #bf0303">

<div class="sourceCode" id="cb10"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb10-1"><a href="#cb10-1"></a>auto update_inner = [this](range_reference_t&lt;<em>Base</em>&gt; x) -&gt; auto&amp; {</span>
<span id="cb10-2"><a href="#cb10-2"></a>  if constexpr (<em>ref-is-glvalue</em>) // x is a reference</span>
<span id="cb10-3"><a href="#cb10-3"></a>    return x;</span>
<span id="cb10-4"><a href="#cb10-4"></a>  else</span>
<span id="cb10-5"><a href="#cb10-5"></a>    return (<em>parent_</em>-&gt;<em>inner_</em> = views::all(std::move(x)));</span>
<span id="cb10-6"><a href="#cb10-6"></a>};</span></code></pre></div>

</div>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb11"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>auto update_inner = [this](const iterator_t&lt;<em>Base</em>&gt;&amp; x) -&gt; auto&amp;&amp; {</span>
<span id="cb11-2"><a href="#cb11-2"></a>  if constexpr (<em>ref-is-glvalue</em>) // *x is a reference</span>
<span id="cb11-3"><a href="#cb11-3"></a>    return *x;</span>
<span id="cb11-4"><a href="#cb11-4"></a>  else</span>
<span id="cb11-5"><a href="#cb11-5"></a>    return <em>parent_</em>-&gt;<em>inner_</em>.<em>emplace-deref</em>(x);</span>
<span id="cb11-6"><a href="#cb11-6"></a>};</span></code></pre></div>

</div>
<div class="dummy">
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="cf">for</span> <span class="op">(</span>; <em>outer_</em> <span class="op">!=</span> ranges<span class="op">::</span>end<span class="op">(</span><em>parent_</em><span class="op">-&gt;</span><em>base_</em><span class="op">)</span>; <span class="op">++</span><em>outer_</em><span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2"></a>  <span class="kw">auto</span><span class="op">&amp;</span><span class="diffins">&amp;</span> inner <span class="op">=</span> update_inner<span class="op">(</span><span class="diffdel">*</span><em>outer_</em><span class="op">)</span>;</span>
<span id="cb12-3"><a href="#cb12-3"></a>  <em>inner_</em> <span class="op">=</span> ranges<span class="op">::</span>begin<span class="op">(</span>inner<span class="op">)</span>;</span>
<span id="cb12-4"><a href="#cb12-4"></a>  <span class="cf">if</span> <span class="op">(</span><em>inner_</em> <span class="op">!=</span> ranges<span class="op">::</span>end<span class="op">(</span>inner<span class="op">))</span></span>
<span id="cb12-5"><a href="#cb12-5"></a>    <span class="cf">return</span>;</span>
<span id="cb12-6"><a href="#cb12-6"></a><span class="op">}</span></span>
<span id="cb12-7"><a href="#cb12-7"></a><span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><em>ref-is-glvalue</em><span class="op">)</span></span>
<span id="cb12-8"><a href="#cb12-8"></a>  <em>inner_</em> <span class="op">=</span> iterator_t<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>Base<span class="op">&gt;&gt;()</span>;</span></code></pre></div>
</div>
<p>[…]</p>
</blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">constexpr</span> <em>iterator</em><span class="op">&amp;</span> <span class="kw">operator</span><span class="op">++()</span>;</span></code></pre></div>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span> Let <em><code class="sourceCode cpp">inner<span class="op">-</span>range</code></em> be:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span> If <em><code class="sourceCode cpp">ref<span class="op">-</span>is<span class="op">-</span>glvalue</code></em> is true, <em><code class="sourceCode cpp"><span class="op">*</span>outer_</code></em>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span> Otherwise, <code class="sourceCode cpp"><span class="diffins">*</span><em>parent_</em><span class="op">-&gt;</span><em>inner_</em></code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span> <em>Effects:</em> Equivalent to:</p>
<div class="dummy">
<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">auto</span><span class="op">&amp;&amp;</span> inner_rng <span class="op">=</span> <em>inner-range</em>;</span>
<span id="cb14-2"><a href="#cb14-2"></a><span class="cf">if</span> <span class="op">(++</span><em>inner_</em> <span class="op">==</span> ranges<span class="op">::</span>end<span class="op">(</span>inner_rng<span class="op">))</span> <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3"></a>  <span class="op">++</span><em>outer_</em>;</span>
<span id="cb14-4"><a href="#cb14-4"></a>  <em>satisfy</em><span class="op">()</span>;</span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="op">}</span></span>
<span id="cb14-6"><a href="#cb14-6"></a><span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>;</span></code></pre></div>
</div>
</blockquote>
</div>
</blockquote>
<ol start="5" type="1">
<li>Modify <span>24.7.11.4 <a href="https://wg21.link/range.join.sentinel">[range.join.sentinel]</a></span> as indicated:</li>
</ol>
<blockquote>
<div>
<div class="sourceCode" id="cb15"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb15-1"><a href="#cb15-1"></a>namespace std::ranges {</span>
<span id="cb15-2"><a href="#cb15-2"></a>  template&lt;input_range V&gt;</span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="st">-    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt; <span class="diffdel">&amp;&amp;</span></span></span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="va">+    requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;</span></span>
<span id="cb15-5"><a href="#cb15-5"></a><span class="st">-             (is_reference_v&lt;range_reference_t&lt;V&gt;&gt; ||</span></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="st">-              view&lt;range_value_t&lt;V&gt;&gt;)</span></span>
<span id="cb15-7"><a href="#cb15-7"></a>  template&lt;bool Const&gt;</span>
<span id="cb15-8"><a href="#cb15-8"></a>  struct join_view&lt;V&gt;::<em>sentinel</em> {</span>
<span id="cb15-9"><a href="#cb15-9"></a>    [...]</span>
<span id="cb15-10"><a href="#cb15-10"></a>  };</span>
<span id="cb15-11"><a href="#cb15-11"></a>}</span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-P2214R0">
<p>[P2214R0] Barry Revzin, Conor Hoekstra, Tim Song. 2020-10-15. A Plan for C++23 Ranges. <br />
<a href="https://wg21.link/p2214r0">https://wg21.link/p2214r0</a></p>
</div>
<div id="ref-P2231R1">
<p>[P2231R1] Barry Revzin. 2021-02-12. Add further constexpr support for optional/variant. <br />
<a href="https://wg21.link/p2231r1">https://wg21.link/p2231r1</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
