<!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-09-14" />
  <title>A Plan for C++23 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 { 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">A Plan for C++23 Ranges</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2214R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-09-14</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>
      Conor Hoekstra<br>&lt;<a href="mailto:conorhoekstra@gmail.com" class="email">conorhoekstra@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="#view-adjuncts"><span class="toc-section-number">3</span> View adjuncts<span></span></a></li>
<li><a href="#views"><span class="toc-section-number">4</span> Views<span></span></a>
<ul>
<li><a href="#full-view-or-not-full-view"><span class="toc-section-number">4.1</span> Full view or not full view<span></span></a></li>
<li><a href="#the-zip-family"><span class="toc-section-number">4.2</span> The <code class="sourceCode cpp">zip</code> family<span></span></a>
<ul>
<li><a href="#a-tuple-that-is-writable"><span class="toc-section-number">4.2.1</span> A <code class="sourceCode cpp">tuple</code> that is <code class="sourceCode cpp">writable</code><span></span></a></li>
<li><a href="#a-tuple-that-is-readable"><span class="toc-section-number">4.2.2</span> A <code class="sourceCode cpp">tuple</code> that is <code class="sourceCode cpp">readable</code><span></span></a></li>
<li><a href="#zip-and-zip_transforms-value_type"><span class="toc-section-number">4.2.3</span> <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">zip_transform</code>’s <code class="sourceCode cpp">value_type</code><span></span></a></li>
<li><a href="#enumerates-first-range"><span class="toc-section-number">4.2.4</span> <code class="sourceCode cpp">enumerate</code>’s first range<span></span></a></li>
<li><a href="#does-adjacent-mean-2-or-n"><span class="toc-section-number">4.2.5</span> Does <code class="sourceCode cpp">adjacent</code> mean <code class="sourceCode cpp"><span class="dv">2</span></code> or <code class="sourceCode cpp">n</code>?<span></span></a></li>
</ul></li>
<li><a href="#the-group_by-family"><span class="toc-section-number">4.3</span> The <code class="sourceCode cpp">group_by</code> family<span></span></a></li>
<li><a href="#monadic-binds"><span class="toc-section-number">4.4</span> Monadic binds<span></span></a>
<ul>
<li><a href="#flat_map"><span class="toc-section-number">4.4.1</span> <code class="sourceCode cpp">flat_map</code><span></span></a></li>
<li><a href="#transform_maybe"><span class="toc-section-number">4.4.2</span> <code class="sourceCode cpp">transform_maybe</code><span></span></a></li>
</ul></li>
<li><a href="#the-sliding-family"><span class="toc-section-number">4.5</span> The sliding family<span></span></a></li>
<li><a href="#the-takedrop-family"><span class="toc-section-number">4.6</span> The take/drop family<span></span></a></li>
<li><a href="#generative-factories"><span class="toc-section-number">4.7</span> Generative factories<span></span></a></li>
<li><a href="#other-view-adapters"><span class="toc-section-number">4.8</span> Other view adapters<span></span></a></li>
<li><a href="#derivatives-of-transform"><span class="toc-section-number">4.9</span> Derivatives of <code class="sourceCode cpp">transform</code><span></span></a>
<ul>
<li><a href="#viewsas_const"><span class="toc-section-number">4.9.1</span> <code class="sourceCode cpp">views<span class="op">::</span>as_const</code><span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#algorithms"><span class="toc-section-number">5</span> Algorithms<span></span></a>
<ul>
<li><a href="#algorithms-that-output-a-value-catamorphisms"><span class="toc-section-number">5.1</span> Algorithms that Output a Value (Catamorphisms)<span></span></a>
<ul>
<li><a href="#stdaccumulate-rangesfold"><span class="toc-section-number">5.1.1</span> <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code><span></span></a></li>
<li><a href="#rangesreduce"><span class="toc-section-number">5.1.2</span> <code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code><span></span></a></li>
<li><a href="#rangestransform_reduce-and-rangesinner_product"><span class="toc-section-number">5.1.3</span> <code class="sourceCode cpp">ranges<span class="op">::</span>transform_reduce</code> and <code class="sourceCode cpp">ranges<span class="op">::</span>inner_product</code><span></span></a></li>
</ul></li>
<li><a href="#algorithms-that-output-a-range-anamorphisms"><span class="toc-section-number">5.2</span> Algorithms that Output a Range (Anamorphisms)<span></span></a>
<ul>
<li><a href="#shift_left-and-shift_right"><span class="toc-section-number">5.2.1</span> <code class="sourceCode cpp">shift_left</code> and <code class="sourceCode cpp">shift_right</code><span></span></a></li>
<li><a href="#stdadjacent_difference-rangesadjacent_transform"><span class="toc-section-number">5.2.2</span> <code class="sourceCode cpp">std<span class="op">::</span>adjacent_difference</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>adjacent_transform</code><span></span></a></li>
<li><a href="#stdpartial_sum-rangespartial_fold-and-stdinexclusive_scan"><span class="toc-section-number">5.2.3</span> <code class="sourceCode cpp">std<span class="op">::</span>partial_sum</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>partial_fold</code> and <code class="sourceCode cpp">std<span class="op">::{</span>in,ex<span class="op">}</span>clusive_scan</code><span></span></a></li>
<li><a href="#transform_inexclusive_scan"><span class="toc-section-number">5.2.4</span> <code class="sourceCode cpp">transform_<span class="op">{</span>in,ex<span class="op">}</span>clusive_scan</code><span></span></a></li>
</ul></li>
<li><a href="#parallel-algorithms"><span class="toc-section-number">5.3</span> Parallel Algorithms<span></span></a></li>
</ul></li>
<li><a href="#actions"><span class="toc-section-number">6</span> Actions<span></span></a></li>
<li><a href="#plan-summary"><span class="toc-section-number">7</span> Plan Summary<span></span></a>
<ul>
<li><a href="#tier-1"><span class="toc-section-number">7.1</span> <span class="addu">Tier 1</span><span></span></a></li>
<li><a href="#tier-2"><span class="toc-section-number">7.2</span> <span class="yellow">Tier 2</span><span></span></a></li>
<li><a href="#tier-3"><span class="toc-section-number">7.3</span> <span class="diffdel">Tier 3</span><span></span></a></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">8</span> References<span></span></a></li>
</ul>
</div>
<style type="text/css">
span.orange {
    background-color: #ffa500;
}
span.yellow {
    background-color: #ffff00;
}
</style>
<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="P2214R0">[<a href="#ref-P2214R0" role="doc-biblioref">P2214R0</a>]</span>, updating with progress and links to other papers. Several changes have been made here:</p>
<ul>
<li>Pipe support for range adaptors has been added as a Tier 1 priority.</li>
<li><code class="sourceCode cpp">cache1</code> has been lowered from Tier 1 to Tier 2 due to inherent issues with its design.</li>
<li><code class="sourceCode cpp">as_const</code> has been upgraded from Tier 3 to Tier 1 due to demand (and renamed from <code class="sourceCode cpp">const_</code>).</li>
<li><code class="sourceCode cpp">flat_map</code> has been lowered to Tier 3 (since now <code class="sourceCode cpp">transform<span class="op">(</span>f<span class="op">)</span> <span class="op">|</span> join</code> is correct for all cases).</li>
<li><code class="sourceCode cpp">transform_maybe</code> has been lowered to Tier 2 (since it depends on <code class="sourceCode cpp">cache1</code>)</li>
<li>the various set range adaptors were omitted previously, and are added as Tier 3.</li>
<li>two more algorithms that weren’t rangified for C++20 added as Tier 1: <code class="sourceCode cpp">shift_left</code> and <code class="sourceCode cpp">shift_right</code>.</li>
<li>added more color to the discussion of <code class="sourceCode cpp">chunk_by</code></li>
</ul>
<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>When Ranges was merged into C++20 <span class="citation" data-cites="P0896R4">[<a href="#ref-P0896R4" role="doc-biblioref">P0896R4</a>]</span>, it was knowingly incomplete. While it was based on the implementation experience in range-v3 <span class="citation" data-cites="range-v3">[<a href="#ref-range-v3" role="doc-biblioref">range-v3</a>]</span>, only a small part of that library was adopted into C++20. The Ranges proposal was big enough already, a lot of the pieces were separable and so could be included later.</p>
<p>But now that the core of Ranges has been included, later has come and we have to figure out what to do for C++23. This is a particularly trying period in the committee’s history with the global pandemic and lack of face-to-face meetings. But we do already have a plan for C++23 <span class="citation" data-cites="P0592R4">[<a href="#ref-P0592R4" role="doc-biblioref">P0592R4</a>]</span> which laid out the following priorities:</p>
<div class="quote">
<p>The priority order of handling material is thus:</p>
<ol type="1">
<li>Material that is mentioned in this plan.</li>
<li>Bug fixes, performance improvements, integration fixes for/between existing features, and issue processing.</li>
<li>Material that is not mentioned in this plan.</li>
</ol>
</div>
<p>and</p>
<div class="quote">
<p>Where are nex-gen Ranges in this plan?</p>
<p>We could certainly entertain more Actions and Views in the realm of Ranges. Whether such material appears for standardization is a bit unknown at this point.</p>
</div>
<p>We believe that adding more functionality to Ranges is important, even if it would technically be a 3rd priority item (unless you consider the spirit of the 2nd priority to include integration with itself).</p>
<p>But there is a <em>lot</em> of outstanding functionality that could be added. And while we think all of it should eventually be added (having more algorithms and more views is always a good thing), we realize that this is may be too much even in the C++23 time frame. Rather than having one-off papers that propose one bit of functionality (as in <span class="citation" data-cites="P1255R6">[<a href="#ref-P1255R6" role="doc-biblioref">P1255R6</a>]</span>, <span class="citation" data-cites="P1894R0">[<a href="#ref-P1894R0" role="doc-biblioref">P1894R0</a>]</span>, or <span class="citation" data-cites="P2164R5">[<a href="#ref-P2164R5" role="doc-biblioref">P2164R5</a>]</span>), we think it’s important to take a big picture view of what is out there and triage the various parts into three separate buckets:</p>
<ol type="1">
<li>Functionality that is really important for C++23. That which is frequently used and broadly applicable, and thus whose absence is frequently complained about.</li>
<li>Functionality that would be nice to have for C++23. Not as frequently needed as the first bucket, but still clearly want it in the standard - but more tolerable if this slips. Ideally C++23 anyway, but simply less critical.</li>
<li>Functionality that is less important or needs more design work.</li>
</ol>
<p>This paper provides our opinion for how to categorize Ranges functionality into those three buckets. We go through, in turn: <a href="#view-adjuncts">views-adjacent functionality</a>, <a href="#views">views</a>, <a href="#algorithms">algorithms</a>, and <a href="#actions">actions</a> (which do not exist in C++20).</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="view-adjuncts"><span class="header-section-number">3</span> View adjuncts<a href="#view-adjuncts" class="self-link"></a></h1>
<p>C++20 Ranges, and the range-v3 that birthed it, isn’t just a collection of loosely related views and algorithms. There’s some important other functionality there.</p>
<p>One critical piece of missing functionality is <span class="addu"><code class="sourceCode cpp">ranges<span class="op">::</span>to</code> <span class="citation" data-cites="P1206R6">[<a href="#ref-P1206R6" role="doc-biblioref">P1206R6</a>]</span></span>. It’s not a view, but it is often used as the terminal component of a view pipeline to create a new trailing range - to finally collect the results of the computation being constructed. This is a top priority and is sorely missing.</p>
<p>Another criticial piece of functionality was pointed out by Walter Brown in the telecon discussing the initial draft of this paper: it is simply not possible for users to write their own range adaptors such that they smoothly interact with standard library (or other user) range adaptors. That is, it is possible (but a little tedious) for users to write an adaptor such that they can write <code class="sourceCode cpp">r <span class="op">|</span> my<span class="op">::</span>thing <span class="op">|</span> my<span class="op">::</span>func<span class="op">(</span><span class="dv">2</span><span class="op">)</span></code>, but it is <em>not</em> possible for them to write an adaptor such that they can write:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">auto</span> adaptor <span class="op">=</span> my<span class="op">::</span>thing <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">(</span>f<span class="op">)</span> <span class="op">|</span> my<span class="op">::</span>func<span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">auto</span> result <span class="op">=</span> r <span class="op">|</span> adaptor;</span></code></pre></div>
<p>In order to do that, standard library adaptors need to recognize user-defined adaptors as being adaptors. That needs library help and is also a top priority - since if users can define more adaptors, it becomes less critical that the standard library provide all of them. The standard library needs to provide <span class="addu">pipe support for user-defined adaptors <span class="citation" data-cites="P2387R1">[<a href="#ref-P2387R1" role="doc-biblioref">P2387R1</a>]</span></span></p>
<p>Another important piece of functionality is simply the ability to print views. In range-v3, views were printable, which made it easy to debug programs or to provide meaningful output. For instance, the following program using range-v3 happily compiles:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/iota.hpp&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/transform.hpp&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/filter.hpp&gt;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5"></a></span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-7"><a href="#cb2-7"></a>    <span class="kw">namespace</span> rv <span class="op">=</span> ranges<span class="op">::</span>views;</span>
<span id="cb2-8"><a href="#cb2-8"></a>    <span class="kw">auto</span> r <span class="op">=</span> rv<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">20</span><span class="op">)</span></span>
<span id="cb2-9"><a href="#cb2-9"></a>           <span class="op">|</span> rv<span class="op">::</span>filter<span class="op">([](</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> i <span class="op">%</span> <span class="dv">2</span> <span class="op">==</span> <span class="dv">0</span>; <span class="op">})</span></span>
<span id="cb2-10"><a href="#cb2-10"></a>           <span class="op">|</span> rv<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>
<span id="cb2-11"><a href="#cb2-11"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> r;</span>
<span id="cb2-12"><a href="#cb2-12"></a><span class="op">}</span></span></code></pre></div>
<p>and prints <code class="sourceCode cpp"><span class="op">[</span><span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">16</span>,<span class="dv">36</span>,<span class="dv">64</span>,<span class="dv">100</span>,<span class="dv">144</span>,<span class="dv">196</span>,<span class="dv">256</span>,<span class="dv">324</span><span class="op">]</span></code>.</p>
<p>Similarly, fmtlib supports printing ranges with <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>, which is slightly more tedious but is at least still a single line:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/iota.hpp&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/transform.hpp&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="pp">#include </span><span class="im">&lt;range/v3/view/filter.hpp&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="pp">#include </span><span class="im">&lt;fmt/format.h&gt;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a></span>
<span id="cb3-6"><a href="#cb3-6"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>    <span class="kw">namespace</span> rv <span class="op">=</span> ranges<span class="op">::</span>views;</span>
<span id="cb3-8"><a href="#cb3-8"></a>    <span class="kw">auto</span> r <span class="op">=</span> rv<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">20</span><span class="op">)</span></span>
<span id="cb3-9"><a href="#cb3-9"></a>           <span class="op">|</span> rv<span class="op">::</span>filter<span class="op">([](</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> i <span class="op">%</span> <span class="dv">2</span> <span class="op">==</span> <span class="dv">0</span>; <span class="op">})</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>           <span class="op">|</span> rv<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>
<span id="cb3-11"><a href="#cb3-11"></a>    fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;[{}]&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>r, <span class="st">&quot;,&quot;</span><span class="op">))</span>;</span>
<span id="cb3-12"><a href="#cb3-12"></a><span class="op">}</span></span></code></pre></div>
<p>But neither the ability to stream views directly nor <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> are in C++20, so there is no direct way to print a range at all.</p>
<p>We think it’s important that C++23 provides the ability to <span class="addu">format all the ranges <span class="citation" data-cites="P2286R2">[<a href="#ref-P2286R2" role="doc-biblioref">P2286R2</a>]</span></span>. Since these are all standard library types, it is difficult for the user to be able to actually do this themselves and it’s frustrating to even have to.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="views"><span class="header-section-number">4</span> Views<a href="#views" class="self-link"></a></h1>
<p>C++20 included a bunch of views, but range-v3 has a whole lot more. Views, much like algorithms, are the kind of thing where it’s just generally good to have more of them. The C++20 standard library has over 100 algorithms, but only 17 range adapters and view factories (excluding <code class="sourceCode cpp">all</code> and <code class="sourceCode cpp">ref</code>). We want more.</p>
<p>We’ll start this section by enumerating all the adapters in range-v3 (and a few that aren’t), noting their current status, and ranking them according to our view of their priority for C++23, before describing how we came up with such a ranking.</p>
<table>
<colgroup>
<col style="width: 36%"></col>
<col style="width: 39%"></col>
<col style="width: 24%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>View</strong>
</div></th>
<th><div style="text-align:center">
<strong>Current Status</strong>
</div></th>
<th><div style="text-align:center">
<strong>Proposed Priority</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">addressof</code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">adjacent</code></td>
<td>(not in range-v3)</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span></span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">adjacent_transform</code></td>
<td>(not in range-v3)</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">adjacent_filter</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">adjacent_remove_if</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">all</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">any_view<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">c_str</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">cache1</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2. Possibly renamed as <code class="sourceCode cpp">cache_last</code> or <code class="sourceCode cpp">cache_latest</code></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">cartesian_product</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2374R1">[<a href="#ref-P2374R1" role="doc-biblioref">P2374R1</a>]</span></span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">chunk</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">chunk_by</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2443R0">[<a href="#ref-P2443R0" role="doc-biblioref">P2443R0</a>]</span></span>. This is an improved <a href="#the-group_by-family"><code class="sourceCode cpp">group_by</code></a> recently added to range-v3. <span class="yellow">Also consider a variant <code class="sourceCode cpp">chunk_on</code> as Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">common</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">concat</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">const_</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2278R1">[<a href="#ref-P2278R1" role="doc-biblioref">P2278R1</a>]</span>, renamed to <code class="sourceCode cpp">as_const</code></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">counted</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">cycle</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">delimit</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">drop</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">drop_last</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">drop_last_while</code></td>
<td>(not in range-v3)</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">drop_exactly</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">drop_while</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">empty</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">enumerate</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2164R5">[<a href="#ref-P2164R5" role="doc-biblioref">P2164R5</a>]</span></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">filter</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">for_each</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3. Most languages call this <code class="sourceCode cpp">flat_map</code>, but we probably need to call it <code class="sourceCode cpp">transform_join</code>. <br />This is now completely supported as <code class="sourceCode cpp">transform<span class="op">(</span>f<span class="op">)</span> <span class="op">|</span> join</code></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">generate</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">generate_n</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">group_by</code></td>
<td>range-v3</td>
<td>Not proposed. See <a href="#the-group_by-family"><code class="sourceCode cpp">group_by</code> discussion</a></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">head</code></td>
<td>(not in range-v3)</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">indirect</code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">intersperse</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">ints</code></td>
<td>range-v3</td>
<td>Unnecessary unless people really hate <code class="sourceCode cpp">iota</code>.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">iota</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">join</code></td>
<td>partially C++20, lacks delimiter ability</td>
<td><span class="addu">Tier 1 (adding delimiter ability via <code class="sourceCode cpp">join_with</code> <span class="citation" data-cites="P2441R0">[<a href="#ref-P2441R0" role="doc-biblioref">P2441R0</a>]</span>)</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">keys</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">linear_distribute</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">maybe</code></td>
<td>proposed in <span class="citation" data-cites="P1255R6">[<a href="#ref-P1255R6" role="doc-biblioref">P1255R6</a>]</span></td>
<td>???</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">move</code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">partial_sum</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2, but not taking a callable (solely as a specialized form of <code class="sourceCode cpp">scan</code>)</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">remove</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">remove_if</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">repeat</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">repeat_n</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">replace</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">replace_if</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">reverse</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">sample</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">scan</code></td>
<td>(not in range-v3)</td>
<td><span class="yellow">Tier 2, as a rename of what is <code class="sourceCode cpp">partial_sum</code> in range-v3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">set_difference</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">set_intersection</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">set_union</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">set_symmetric_difference</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">single</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">slice</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">sliding</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1, renamed to <code class="sourceCode cpp">slide</code> <span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">split</code></td>
<td>C++20, but unergonomic</td>
<td>See <span class="citation" data-cites="P2210R0">[<a href="#ref-P2210R0" role="doc-biblioref">P2210R0</a>]</span>.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">split_when</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">stride</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P1899R0">[<a href="#ref-P1899R0" role="doc-biblioref">P1899R0</a>]</span></span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">tail</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">take</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">take_exactly</code></td>
<td>range-v3</td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">take_last</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">take_last_while</code></td>
<td>(not in range-v3)</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">take_while</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">tokenize</code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">transform_maybe</code></td>
<td>(not in range-v3)</td>
<td><span class="yellow">Tier 2, as a more ergonomic <code class="sourceCode cpp">maybe</code> (Haskell calls this <code class="sourceCode cpp">mapMaybe</code>, Rust calls this <code class="sourceCode cpp">filter_map</code>)</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">trim</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">unbounded</code></td>
<td>range-v3</td>
<td>Not proposed</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">unique</code></td>
<td>range-v3</td>
<td><span class="yellow">Tier 2</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">values</code></td>
<td>C++20</td>
<td>C++20</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">zip</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1 <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span></span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">zip_with</code></td>
<td>range-v3</td>
<td><span class="addu">Tier 1, renamed to <code class="sourceCode cpp">zip_transform</code> <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span></span></td>
</tr>
</tbody>
</table>
<h2 data-number="4.1" id="full-view-or-not-full-view"><span class="header-section-number">4.1</span> Full view or not full view<a href="#full-view-or-not-full-view" class="self-link"></a></h2>
<p>One question we have to ask is which of these views need to be full-blown view types and which do not. This is an important question to deal with in light of the very real limitation that is LWG’s bandwidth. Views that need to be full types necessitate more longer and more complex specification which require more LWG time. Views that need <em>not</em> be full types could save some time.</p>
<p>Consider <code class="sourceCode cpp">views<span class="op">::</span>tail</code>. This is a very simple range adapter that simply drops its first element. As such, it could be specified entirely as:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">namespace</span> std<span class="op">::</span>ranges<span class="op">::</span>views <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> tail <span class="op">=</span> drop<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb4-3"><a href="#cb4-3"></a><span class="op">}</span></span></code></pre></div>
<p>The above is a semantically correct implementation. However, is it the implementation we would actually want for <code class="sourceCode cpp">views<span class="op">::</span>tail</code>? There are a few extra things <code class="sourceCode cpp">views<span class="op">::</span>drop</code> has to do. <code class="sourceCode cpp">views<span class="op">::</span>drop</code> must store a count and a cache for the begin iterator for forward ranges (to satisfy <code class="sourceCode cpp">O<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code>), but <code class="sourceCode cpp">views<span class="op">:</span>tail</code> has to do none of these things since 1 is a constant and invoking <code class="sourceCode cpp">next<span class="op">()</span></code> one time still satisfies <code class="sourceCode cpp">O<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code>.</p>
<p>This puts us in an interesting position: we either adopt a known suboptimal implementation of <code class="sourceCode cpp">tail</code> with minimal LWG cost (such that we could likely adopt this for C++23) or we could hold off for the optimal implementation (in which case we could not in good conscience put <code class="sourceCode cpp">tail</code> as a Tier 1 view, as it is certainly not that important). As such, we have tentatively marked it as Tier 3.</p>
<p>Take a different view, <code class="sourceCode cpp">unbounded</code>. A perfectly valid implementation of it, in its entirely is:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">namespace</span> std<span class="op">::</span>ranges<span class="op">::</span>views <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> unbounded <span class="op">=</span> <span class="op">[](</span>input_iterator <span class="kw">auto</span> it<span class="op">){</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>        <span class="cf">return</span> subrange<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>it<span class="op">)</span>, unreachable_sentinel<span class="op">)</span>;</span>
<span id="cb5-4"><a href="#cb5-4"></a>    <span class="op">}</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="op">}</span></span></code></pre></div>
<p>Unlike <code class="sourceCode cpp">tail</code>, there isn’t really some other, better implementation here. Maybe we’d prefer to give <code class="sourceCode cpp">unbounded_view<span class="op">&lt;</span>I<span class="op">&gt;</span></code> its own type rather than piggy-backing off of <code class="sourceCode cpp">subrange</code>, but it wouldn’t really affect the choice of functionality overall. Here the question is less, do we do it fast for C++23 or do it right for C++26 or C++20. Rather, the question is more: do we even need this at all? We think we don’t.</p>
<p>Consider two different, closely related views: <code class="sourceCode cpp">views<span class="op">::</span>zip</code> and <code class="sourceCode cpp">views<span class="op">::</span>zip_transform</code> (which range-v3 calls <code class="sourceCode cpp">zip_with</code>). Each could potentially be specified in terms of the other:</p>
<ul>
<li><code class="sourceCode cpp">views<span class="op">::</span>zip<span class="op">(</span>Es<span class="op">...)</span></code> could be <code class="sourceCode cpp">views<span class="op">::</span>zip_transform<span class="op">(</span><em>forward-as-tuple</em>, Es<span class="op">...)</span></code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>zip_transform<span class="op">(</span>F, Es<span class="op">...)</span></code> could be <code class="sourceCode cpp">views<span class="op">::</span>zip<span class="op">(</span>Es<span class="op">...)</span> <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span><em>applied</em><span class="op">(</span>F<span class="op">))</span></code></li>
</ul>
<p>where <code class="sourceCode cpp"><em>forward-as-tuple</em></code> is a function object version of <code class="sourceCode cpp">std<span class="op">::</span>forward_as_tuple</code> and <code class="sourceCode cpp"><em>applied</em><span class="op">(</span>F<span class="op">)(</span>x<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">std<span class="op">::</span>apply<span class="op">(</span>F, x<span class="op">)</span></code>.</p>
<p>But they’re not <em>quite</em> equivalent — they differ in their handling of ranges that produce prvalues. <code class="sourceCode cpp">zip_transform</code> can’t differentiate between prvalues and xvalues, while <code class="sourceCode cpp">zip</code> would need to, so we lose that distinction by implementing <code class="sourceCode cpp">zip</code> in terms of <code class="sourceCode cpp">zip_transform</code>.</p>
<p>Likewise, a first-class <code class="sourceCode cpp">zip_transform</code> would construct those prvalues directly into the parameters of the function that gets passed in; whereas if we implemented <code class="sourceCode cpp">zip_transform</code> in terms of <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">transform</code> those prvalues would have to first be materialized into a <code class="sourceCode cpp">tuple</code> and then moved into the function.</p>
<p>Even though these two views are very, very similar to each other, we still don’t want to specify one in terms of the other even if it means more specification effort. And we still propose that both be Tier 1 views due to their overall importance. It would be better to adopt <code class="sourceCode cpp">zip</code> on its own and provide a new function adapter <code class="sourceCode cpp"><em>applied</em></code>, leaving the door open to a better <code class="sourceCode cpp">zip_transform</code> in the future, than specify <code class="sourceCode cpp">zip_transform</code> in terms of <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">transform</code>.</p>
<p>Another interesting example is <code class="sourceCode cpp">transform_maybe</code>. As we’ll see later, <code class="sourceCode cpp">transform_maybe<span class="op">(</span>E, F<span class="op">)</span></code> can easily be specified in terms of three adapters today (a <code class="sourceCode cpp">transform</code> followed by a <code class="sourceCode cpp">filter</code> followed by a <code class="sourceCode cpp">transform</code>). But while <code class="sourceCode cpp">tail</code> can be made a little bit better as a standalone view, <code class="sourceCode cpp">transform_maybe</code> can be <em>substantially</em> improved.</p>
<p>Ultimately, this question of full view or not fill view is one that should guide review of this paper.</p>
<h2 data-number="4.2" id="the-zip-family"><span class="header-section-number">4.2</span> The <code class="sourceCode cpp">zip</code> family<a href="#the-zip-family" class="self-link"></a></h2>
<p>The <code class="sourceCode cpp">zip</code> family of range adapters is an extremely useful set of adapters with broad applicability (and is now proposed in <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>). It consists of five user-facing range adapters:</p>
<ol type="1">
<li><code class="sourceCode cpp">zip</code></li>
<li><code class="sourceCode cpp">zip_transform</code> — <code class="sourceCode cpp">zip_with</code> in range-v3</li>
<li><code class="sourceCode cpp">enumerate</code> — <code class="sourceCode cpp">enumerate<span class="op">(</span>E<span class="op">)</span></code> is <a href="#enumerates-first-range">roughly equivalent</a> to <code class="sourceCode cpp">zip<span class="op">(</span>iota<span class="op">(</span><span class="dv">0</span><span class="op">)</span>, E<span class="op">)</span></code></li>
<li><code class="sourceCode cpp">adjacent</code> — <code class="sourceCode cpp">adjacent<span class="op">(</span>E<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">zip<span class="op">(</span>E, E <span class="op">|</span> drop<span class="op">(</span><span class="dv">1</span><span class="op">))</span></code></li>
<li><code class="sourceCode cpp">adjacent_transform</code> — is to <code class="sourceCode cpp">adjacent</code> what <code class="sourceCode cpp">zip_transform</code> is to <code class="sourceCode cpp">zip</code></li>
</ol>
<p>Indeed, we have many algorithms that exist largely because we don’t have <code class="sourceCode cpp">zip</code> (and prior to Ranges, didn’t have the ability to compose algorithms). We have several algorithms that have single-range-unary-function and a two-range-binary-function flavors. What if you wanted to <code class="sourceCode cpp">ranges<span class="op">::</span>transform</code> 3 ranges? Out of luck. But in all of these cases, the two-range-binary-function flavor could be written as a single-range that is a <code class="sourceCode cpp">zip</code> of the two ranges, <code class="sourceCode cpp">adjacent_difference</code> is <code class="sourceCode cpp">adjacent_transform</code>, <code class="sourceCode cpp">inner_product</code> is <code class="sourceCode cpp">zip_transform</code> followed by <code class="sourceCode cpp">accumulate</code>, and so on and so on. This is why we think <code class="sourceCode cpp">zip</code> is the top priority view.</p>
<p>range-v3 uses the name <code class="sourceCode cpp">zip_with</code>, but here we are instead proposing <code class="sourceCode cpp">zip_transform</code>. The reason is that what we’re doing is, quite simply, a <code class="sourceCode cpp">transform</code> and in C++, we don’t really have a strong association of that with the <code class="sourceCode cpp">_with</code> suffix. Instead, we have algorithms like <code class="sourceCode cpp">begins_with</code> and concepts like <code class="sourceCode cpp">swappable_with</code> and <code class="sourceCode cpp">totally_ordered_with</code>, which have nothing to do with this sort of thing.</p>
<p>range-v3 implements <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">zip_with</code> in terms of an underlying adaptor named <code class="sourceCode cpp">iter_zip_with</code>, which takes an <code class="sourceCode cpp">n</code>-ary invocable and <code class="sourceCode cpp">n</code> ranges and combines those into a single range whose values are the result of <code class="sourceCode cpp">f<span class="op">(</span>is<span class="op">...)</span></code>, where the <code class="sourceCode cpp">is</code> are the iterators into those ranges (note: iterators, not what they refer to). The size of an <code class="sourceCode cpp">iter_zip_with</code> is the minimum size of its ranges. The <code class="sourceCode cpp">reference</code> type is the type of <code class="sourceCode cpp">f<span class="op">(*</span>is<span class="op">...)</span></code> while the <code class="sourceCode cpp">value_type</code> is <code class="sourceCode cpp">V</code> (described in more detail <a href="#zip-and-zip_transforms-value_type">later</a> along with the specific choices for <code class="sourceCode cpp"><em>V<sub>zip_transform</sub></em></code> and <code class="sourceCode cpp"><em>V<sub>zip</sub></em></code> used below).</p>
<p>But it turned out that these two views have enough differences that this doesn’t aid in the specification effort that much, and so <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span> did not do it this way. Instead, <code class="sourceCode cpp">zip_transform_view<span class="op">&lt;</span>F, V<span class="op">...&gt;</span></code> is specified in terms of a member <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>V<span class="op">...&gt;</span></code>.</p>
<p>Having those two, <code class="sourceCode cpp">enumerate<span class="op">(</span>E<span class="op">)</span></code> is expression-equivalent to <code class="sourceCode cpp">zip<span class="op">(</span><em>index-view</em><span class="op">(</span>E<span class="op">)</span>, E<span class="op">)</span></code>. We will discuss why <code class="sourceCode cpp"><em>index-view</em><span class="op">(</span>E<span class="op">)</span></code> instead of <code class="sourceCode cpp">iota<span class="op">(</span>range_size_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>E<span class="op">)&gt;(</span><span class="dv">0</span><span class="op">)</span></code> <a href="#enumerates-first-range">later</a>.</p>
<p>But we do not want to define <code class="sourceCode cpp">adjacent<span class="op">(</span>E<span class="op">)</span></code> as <code class="sourceCode cpp">zip<span class="op">(</span>E, E <span class="op">|</span> drop<span class="op">(</span><span class="dv">1</span><span class="op">))</span></code>. The primary reason to avoid doing this, and to make <code class="sourceCode cpp">adjacent</code> a first-class view type despite the added specification effort, is that it allows supporting move-only views. On top of that, it has the benefit of not having to store the view twice or the other cruft that <code class="sourceCode cpp">drop</code> has to store (see also the <code class="sourceCode cpp">drop</code>/<code class="sourceCode cpp">tail</code> discussion earlier).</p>
<p>Similar to how <code class="sourceCode cpp">zip_transform_view<span class="op">&lt;</span>F, V<span class="op">...&gt;</span></code> is specified in terms of a member <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>V<span class="op">...&gt;</span></code>, <code class="sourceCode cpp">adjacent_transform_view<span class="op">&lt;</span>V, F, N<span class="op">&gt;</span></code> is specified as having a member <code class="sourceCode cpp">adjacent_view<span class="op">&lt;</span>V, N<span class="op">&gt;</span></code>.</p>
<p>In short, we get five extremely useful ranges largely from the price of two of them (plus a lot of boilerplate). Which is why we think they should be considered and adopted as a group.</p>
<p>But in order to actually adopt <code class="sourceCode cpp">zip</code> and friends into C++23, we need to resolve several problems.</p>
<h3 data-number="4.2.1" id="a-tuple-that-is-writable"><span class="header-section-number">4.2.1</span> A <code class="sourceCode cpp">tuple</code> that is <code class="sourceCode cpp">writable</code><a href="#a-tuple-that-is-writable" class="self-link"></a></h3>
<p>Consider the following:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> vi <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb6-2"><a href="#cb6-2"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> vs <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb6-3"><a href="#cb6-3"></a>ranges<span class="op">::</span>sort<span class="op">(</span>views<span class="op">::</span>zip<span class="op">(</span>vi, vs<span class="op">))</span>;</span></code></pre></div>
<p>Does this operation make sense? Definitely! It would be very useful if this compiled. Unfortunately, as-is, it will not. We need to go back and understand <em>why</em> this won’t compile today and what we need to do to fix it.</p>
<p>In <span class="citation" data-cites="range-v3.573">[<a href="#ref-range-v3.573" role="doc-biblioref">range-v3.573</a>]</span>, user Jarod42 pointed out that the following program used to compile, yet provide a non-sensical answer:</p>
<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> C</span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3"></a>    <span class="kw">explicit</span> C<span class="op">(</span>std<span class="op">::</span>string a<span class="op">)</span> <span class="op">:</span> bar<span class="op">(</span>a<span class="op">)</span> <span class="op">{}</span></span>
<span id="cb7-4"><a href="#cb7-4"></a></span>
<span id="cb7-5"><a href="#cb7-5"></a>    std<span class="op">::</span>string bar;</span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="op">}</span>;</span>
<span id="cb7-7"><a href="#cb7-7"></a></span>
<span id="cb7-8"><a href="#cb7-8"></a><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb7-9"><a href="#cb7-9"></a><span class="op">{</span></span>
<span id="cb7-10"><a href="#cb7-10"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>C<span class="op">&gt;</span> cs <span class="op">=</span> <span class="op">{</span> C<span class="op">(</span><span class="st">&quot;z&quot;</span><span class="op">)</span>, C<span class="op">(</span><span class="st">&quot;d&quot;</span><span class="op">)</span>, C<span class="op">(</span><span class="st">&quot;b&quot;</span><span class="op">)</span>, C<span class="op">(</span><span class="st">&quot;c&quot;</span><span class="op">)</span> <span class="op">}</span>;</span>
<span id="cb7-11"><a href="#cb7-11"></a></span>
<span id="cb7-12"><a href="#cb7-12"></a>    ranges<span class="op">::</span>sort<span class="op">(</span>cs <span class="op">|</span> ranges<span class="op">::</span>view<span class="op">::</span>transform<span class="op">([](</span><span class="kw">const</span> C<span class="op">&amp;</span> x<span class="op">)</span> <span class="op">{</span><span class="cf">return</span> x<span class="op">.</span>bar;<span class="op">}))</span>;</span>
<span id="cb7-13"><a href="#cb7-13"></a></span>
<span id="cb7-14"><a href="#cb7-14"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> c <span class="op">:</span> cs<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-15"><a href="#cb7-15"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> c<span class="op">.</span>bar <span class="op">&lt;&lt;</span> std<span class="op">::</span>endl;</span>
<span id="cb7-16"><a href="#cb7-16"></a>    <span class="op">}</span></span>
<span id="cb7-17"><a href="#cb7-17"></a><span class="op">}</span></span></code></pre></div>
<p>The range was <em>not</em> sorted, the emitted output was still in the same order as the input… because we’re sorting a range of <em>prvalue</em> <code class="sourceCode cpp">std<span class="op">::</span>string</code>s, and trying to swap prvalue <code class="sourceCode cpp">std<span class="op">::</span>string</code>s makes little sense because it doesn’t do anything.</p>
<p>But the reason it compiled was that the constraints checked if the iterators were assignable-through, which in this case was equivalent to checking if <code class="sourceCode cpp">std<span class="op">::</span>string<span class="op">()</span> <span class="op">=</span> std<span class="op">::</span>string<span class="op">()</span></code> is a valid expression… and it, unfortunately, is. Assignment operators simply are not reference-qualified - they could not have been for a long time, and they are not now. The question became then - how can the library ensure that the above nonsense <em>does not compile</em>?</p>
<p>As discussed in <span class="citation" data-cites="stl2.381">[<a href="#ref-stl2.381" role="doc-biblioref">stl2.381</a>]</span>:</p>
<div class="quote">
<p>One fix would be to require that <code class="sourceCode cpp"><span class="op">*</span>o</code> return a true reference, but that breaks when <code class="sourceCode cpp"><span class="op">*</span>o</code> returns a proxy reference. The trick is in distinguishing between a prvalue that is a proxy from a prvalue that is just a value. The trick lies in recognizing that a proxy always represents a (logical, if not physical) indirection. As such, adding a <code class="sourceCode cpp"><span class="kw">const</span></code> to the proxy should not effect the mutability of the thing being proxied. Further, if <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(*</span>o<span class="op">)</span></code> is a true reference, then adding <code class="sourceCode cpp"><span class="kw">const</span></code> to it has no effect, which also does not effect the mutability. So the fix is to add <code class="sourceCode cpp"><span class="kw">const</span></code> to <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(*</span>o<span class="op">)</span></code>, <code class="sourceCode cpp"><span class="kw">const_cast</span></code> <code class="sourceCode cpp"><span class="op">*</span>o</code> to that, and then test for writability.</p>
</div>
<p>Which is how we ended up with the <code class="sourceCode cpp">indirectly_writable</code> (the concept formerly known as <code class="sourceCode cpp">Writable</code>) requiring <code class="sourceCode cpp"><span class="kw">const</span></code>-assignability.</p>
<p>Hence, in order to make <code class="sourceCode cpp">ranges<span class="op">::</span>sort<span class="op">(</span>zip<span class="op">(</span>vi, vs<span class="op">))</span></code> compile, we need to make <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>R<span class="op">...&gt;::</span>iterator</code> model <code class="sourceCode cpp">indirectly_writable</code>, which means we need to make <code class="sourceCode cpp">std<span class="op">::</span>tuple</code> const-assignable. That is, adding the following assignment operators, appropriately constrained:</p>
<div>
<div class="sourceCode" id="cb8"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1"></a>  // [tuple.assign], tuple assignment</span>
<span id="cb8-2"><a href="#cb8-2"></a>  constexpr tuple&amp; operator=(const tuple&amp;);</span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="va">+ constexpr tuple&amp; operator=(const tuple&amp;) const;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a>  constexpr tuple&amp; operator=(tuple&amp;&amp;) noexcept(<em>see below</em>);</span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="va">+ constexpr tuple&amp; operator=(tuple&amp;&amp;) const noexcept(<em>see below</em>);</span></span>
<span id="cb8-6"><a href="#cb8-6"></a></span>
<span id="cb8-7"><a href="#cb8-7"></a>  template&lt;class... UTypes&gt;</span>
<span id="cb8-8"><a href="#cb8-8"></a>    constexpr tuple&amp; operator=(const tuple&lt;UTypes...&gt;&amp;);</span>
<span id="cb8-9"><a href="#cb8-9"></a><span class="va">+ template&lt;class... UTypes&gt;</span></span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="va">+   constexpr tuple&amp; operator=(const tuple&lt;UTypes...&gt;&amp;) const;</span></span>
<span id="cb8-11"><a href="#cb8-11"></a>  template&lt;class... UTypes&gt;</span>
<span id="cb8-12"><a href="#cb8-12"></a>    constexpr tuple&amp; operator=(tuple&lt;UTypes...&gt;&amp;&amp;);</span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="va">+ template&lt;class... UTypes&gt;</span></span>
<span id="cb8-14"><a href="#cb8-14"></a><span class="va">+   constexpr tuple&amp; operator=(tuple&lt;UTypes...&gt;&amp;&amp;) const;</span></span></code></pre></div>
</div>
<p><em>Or</em>, rather than change <code class="sourceCode cpp">std<span class="op">::</span>tuple</code>, we can have <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>R<span class="op">...&gt;::</span>value_type</code> and <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>R<span class="op">...&gt;::</span>reference</code> be an entirely different tuple type than <code class="sourceCode cpp">std<span class="op">::</span>tuple</code>, introducing a second tuple type into the standard library: <code class="sourceCode cpp">std2<span class="op">::</span>tuple2</code>. This just seems like a facially terrible idea, we already have one tuple type, we should just have it solve this problem for is.</p>
<p>We therefore propose that <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>T<span class="op">...&gt;</span></code> be const-assignable whenever all of <code class="sourceCode cpp">T<span class="op">...</span></code> are const-assignable. And likewise for <code class="sourceCode cpp">std<span class="op">::</span>pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>, for consistency, the other proxy reference type in the standard libary: <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>.</p>
<h3 data-number="4.2.2" id="a-tuple-that-is-readable"><span class="header-section-number">4.2.2</span> A <code class="sourceCode cpp">tuple</code> that is <code class="sourceCode cpp">readable</code><a href="#a-tuple-that-is-readable" class="self-link"></a></h3>
<p>We encourage everyone to review Eric Niebler’s four-part series on iterators <span class="citation" data-cites="niebler.iter.0">[<a href="#ref-niebler.iter.0" role="doc-biblioref">niebler.iter.0</a>]</span> <span class="citation" data-cites="niebler.iter.1">[<a href="#ref-niebler.iter.1" role="doc-biblioref">niebler.iter.1</a>]</span> <span class="citation" data-cites="niebler.iter.2">[<a href="#ref-niebler.iter.2" role="doc-biblioref">niebler.iter.2</a>]</span> <span class="citation" data-cites="niebler.iter.3">[<a href="#ref-niebler.iter.3" role="doc-biblioref">niebler.iter.3</a>]</span>, as this problem is covered in there in some depth.</p>
<p>There is a fundamental problem with standard library algorithms and how they interact with proxy iterators. One example used in the series is <code class="sourceCode cpp">unique_copy</code>:</p>
<div class="quote">
<div class="sourceCode" id="cb9"><pre class="sourceCode numberSource cpp numberLines"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="co">// Copyright (c) 1994</span></span>
<span id="cb9-2"><a href="#cb9-2"></a><span class="co">// Hewlett-Packard Company</span></span>
<span id="cb9-3"><a href="#cb9-3"></a><span class="co">// Copyright (c) 1996</span></span>
<span id="cb9-4"><a href="#cb9-4"></a><span class="co">// Silicon Graphics Computer Systems, Inc.</span></span>
<span id="cb9-5"><a href="#cb9-5"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> InIter, <span class="kw">class</span> OutIter, <span class="kw">class</span> Fn,</span>
<span id="cb9-6"><a href="#cb9-6"></a>          <span class="kw">class</span> _Tp<span class="op">&gt;</span></span>
<span id="cb9-7"><a href="#cb9-7"></a>OutIter</span>
<span id="cb9-8"><a href="#cb9-8"></a>__unique_copy<span class="op">(</span>InIter first, InIter last,</span>
<span id="cb9-9"><a href="#cb9-9"></a>              OutIter result,</span>
<span id="cb9-10"><a href="#cb9-10"></a>              Fn binary_pred, _Tp<span class="op">*)</span> <span class="op">{</span></span>
<span id="cb9-11"><a href="#cb9-11"></a>  _Tp value <span class="op">=</span> <span class="op">*</span>first;</span>
<span id="cb9-12"><a href="#cb9-12"></a>  <span class="op">*</span>result <span class="op">=</span> value;</span>
<span id="cb9-13"><a href="#cb9-13"></a>  <span class="cf">while</span> <span class="op">(++</span>first <span class="op">!=</span> last<span class="op">)</span></span>
<span id="cb9-14"><a href="#cb9-14"></a>    <span class="cf">if</span> <span class="op">(!</span>binary_pred<span class="op">(</span>value, <span class="op">*</span>first<span class="op">))</span> <span class="op">{</span></span>
<span id="cb9-15"><a href="#cb9-15"></a>      value <span class="op">=</span> <span class="op">*</span>first;</span>
<span id="cb9-16"><a href="#cb9-16"></a>      <span class="op">*++</span>result <span class="op">=</span> value;</span>
<span id="cb9-17"><a href="#cb9-17"></a>    <span class="op">}</span></span>
<span id="cb9-18"><a href="#cb9-18"></a>  <span class="cf">return</span> <span class="op">++</span>result;</span>
<span id="cb9-19"><a href="#cb9-19"></a><span class="op">}</span></span></code></pre></div>
<p>[…] Note the value local variable on line 11, and especially note line 14, where it passes a value and a reference to <code class="sourceCode cpp">binary_pred</code>. Keep that in mind because it’s important!</p>
<p>[…] Why do I bring it up? Because it’s <em>super problematic</em> when used with proxy iterators. Think about what happens when you try to pass <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>iterator</code> to the above <code class="sourceCode cpp">__unique_copy</code> function:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span> vb<span class="op">{</span><span class="kw">true</span>, <span class="kw">true</span>, <span class="kw">false</span>, <span class="kw">false</span><span class="op">}</span>;</span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="kw">using</span> R <span class="op">=</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference;</span>
<span id="cb10-3"><a href="#cb10-3"></a>__unique_copy<span class="op">(</span></span>
<span id="cb10-4"><a href="#cb10-4"></a>  vb<span class="op">.</span>begin<span class="op">()</span>, vb<span class="op">.</span>end<span class="op">()</span>,</span>
<span id="cb10-5"><a href="#cb10-5"></a>  std<span class="op">::</span>ostream_iterator<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;{</span>std<span class="op">::</span>cout, <span class="st">&quot; &quot;</span><span class="op">}</span>,</span>
<span id="cb10-6"><a href="#cb10-6"></a>  <span class="op">[](</span>R b1, R b2<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> b1 <span class="op">==</span> b2; <span class="op">}</span>, <span class="op">(</span><span class="dt">bool</span><span class="op">*)</span><span class="dv">0</span> <span class="op">)</span>;</span></code></pre></div>
<p>This <em>should</em> write a “true” and a “false” to <code class="sourceCode cpp">cout</code>, but it doesn’t compile. Why? The lambda is expecting to be passed two objects of <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span></code>‘s proxy reference type, but remember how <code class="sourceCode cpp">__unique_copy</code> calls the predicate:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="cf">if</span> <span class="op">(!</span>binary_pred<span class="op">(</span>value, <span class="op">*</span>first<span class="op">))</span> <span class="op">{</span> <span class="co">/*...*/</span></span></code></pre></div>
<p>That’s a <code class="sourceCode cpp"><span class="dt">bool</span><span class="op">&amp;</span></code> and a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>. Ouch!</p>
</div>
<p>The blog goes on to point out that one way to resolve this is by having the lambda take both parameters as <code class="sourceCode cpp"><span class="kw">auto</span><span class="op">&amp;&amp;</span></code>. But having to <em>require</em> a generic lambda is a bit… much. This was the reason we have the idea of a <code class="sourceCode cpp">common_reference</code>. Rewriting the above to be:</p>
<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">using</span> R <span class="op">=</span> std<span class="op">::</span>iter_common_reference_t<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference<span class="op">&gt;</span>;</span>
<span id="cb12-2"><a href="#cb12-2"></a>__unique_copy<span class="op">(</span></span>
<span id="cb12-3"><a href="#cb12-3"></a>  vb<span class="op">.</span>begin<span class="op">()</span>, vb<span class="op">.</span>end<span class="op">()</span>,</span>
<span id="cb12-4"><a href="#cb12-4"></a>  std<span class="op">::</span>ostream_iterator<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;{</span>std<span class="op">::</span>cout, <span class="st">&quot; &quot;</span><span class="op">}</span>,</span>
<span id="cb12-5"><a href="#cb12-5"></a>  <span class="op">[](</span>R b1, R b2<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> b1 <span class="op">==</span> b2; <span class="op">}</span>, <span class="op">(</span><span class="dt">bool</span><span class="op">*)</span><span class="dv">0</span> <span class="op">)</span>;</span></code></pre></div>
<p>This now works. And that is now the requirement that we have for iterators, that they be <code class="sourceCode cpp">indirectly_readable</code> - which, among other things, requires that there be a <code class="sourceCode cpp">common_reference</code> between the iterator’s <code class="sourceCode cpp">reference</code> type and the iterator’s <code class="sourceCode cpp">value_type<span class="op">&amp;</span></code>:</p>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> In<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2"></a>  <span class="kw">concept</span> <em>indirectly-readable-impl</em> <span class="op">=</span></span>
<span id="cb13-3"><a href="#cb13-3"></a>    <span class="kw">requires</span><span class="op">(</span><span class="kw">const</span> In in<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4"></a>      <span class="kw">typename</span> iter_value_t<span class="op">&lt;</span>In<span class="op">&gt;</span>;</span>
<span id="cb13-5"><a href="#cb13-5"></a>      <span class="kw">typename</span> iter_reference_t<span class="op">&lt;</span>In<span class="op">&gt;</span>;</span>
<span id="cb13-6"><a href="#cb13-6"></a>      <span class="kw">typename</span> iter_rvalue_reference_t<span class="op">&lt;</span>In<span class="op">&gt;</span>;</span>
<span id="cb13-7"><a href="#cb13-7"></a>      <span class="op">{</span> <span class="op">*</span>in <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>iter_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&gt;</span>;</span>
<span id="cb13-8"><a href="#cb13-8"></a>      <span class="op">{</span> ranges<span class="op">::</span>iter_move<span class="op">(</span>in<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>iter_rvalue_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&gt;</span>;</span>
<span id="cb13-9"><a href="#cb13-9"></a>    <span class="op">}</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-10"><a href="#cb13-10"></a>    common_reference_with<span class="op">&lt;</span>iter_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&amp;</span>, iter_value_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-11"><a href="#cb13-11"></a>    common_reference_with<span class="op">&lt;</span>iter_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&amp;</span>, iter_rvalue_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&amp;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-12"><a href="#cb13-12"></a>    common_reference_with<span class="op">&lt;</span>iter_rvalue_reference_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&amp;</span>, <span class="kw">const</span> iter_value_t<span class="op">&lt;</span>In<span class="op">&gt;&amp;&gt;</span>;</span>
<span id="cb13-13"><a href="#cb13-13"></a></span>
<span id="cb13-14"><a href="#cb13-14"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> In<span class="op">&gt;</span></span>
<span id="cb13-15"><a href="#cb13-15"></a>  <span class="kw">concept</span> indirectly_readable <span class="op">=</span></span>
<span id="cb13-16"><a href="#cb13-16"></a>    <em>indirectly-readable-impl</em><span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>In<span class="op">&gt;&gt;</span>;</span>
<span id="cb13-17"><a href="#cb13-17"></a>    </span>
<span id="cb13-18"><a href="#cb13-18"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> I<span class="op">&gt;</span></span>
<span id="cb13-19"><a href="#cb13-19"></a>  <span class="kw">concept</span> input_iterator <span class="op">=</span></span>
<span id="cb13-20"><a href="#cb13-20"></a>    input_or_output_iterator<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-21"><a href="#cb13-21"></a>    indirectly_readable<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-22"><a href="#cb13-22"></a>    <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> <em>ITER_CONCEPT</em><span class="op">(</span>I<span class="op">)</span>; <span class="op">}</span> <span class="op">&amp;&amp;</span></span>
<span id="cb13-23"><a href="#cb13-23"></a>    derived_from<span class="op">&lt;</span><em>ITER_CONCEPT</em><span class="op">(</span>I<span class="op">)</span>, input_iterator_tag<span class="op">&gt;</span>;    </span></code></pre></div>
<p>How does this relate to <code class="sourceCode cpp">zip</code>?</p>
<p>Letting <code class="sourceCode cpp">I</code> be <code class="sourceCode cpp">zip_view<span class="op">&lt;</span>R<span class="op">...&gt;::</span>iterator</code> for some set of ranges <code class="sourceCode cpp">R<span class="op">...</span></code>, it just follows from first principles that <code class="sourceCode cpp">iter_reference_t<span class="op">&lt;</span>I<span class="op">&gt;</span></code> should be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code> — dereferencing a zip iterator should give you a tuple of dereferencing all the underlying ranges’ iterators. And then it sort of follows from symmetry that <code class="sourceCode cpp">iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;</span></code> should be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_value_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code>. We’ll discuss this in more depth <a href="#zip-and-zip_transforms-value_type">in a later section</a>.</p>
<p>But then what does <code class="sourceCode cpp">iter_common_reference_t<span class="op">&lt;</span>I<span class="op">&gt;</span></code> end up being?</p>
<p>Let’s pick some concrete types. Taking our earlier example of:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> vi <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb14-2"><a href="#cb14-2"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> vs <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb14-3"><a href="#cb14-3"></a>ranges<span class="op">::</span>sort<span class="op">(</span>views<span class="op">::</span>zip<span class="op">(</span>vi, vs<span class="op">))</span>;</span></code></pre></div>
<p>We have a value type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code> and a reference type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>. The common reference of those exists: the <code class="sourceCode cpp">reference</code> type is convertible to the value type but not in the other direction, so the common reference is just the value type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code>. This might be odd, having a common <em>reference</em> type that has no reference semantics, but it does work. And in some cases you can’t really do better (as in the <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span></code> example from the blog series, the common reference is <code class="sourceCode cpp"><span class="dt">bool</span></code>).</p>
<p>But where we really run into problems is with non-copyable types. If instead of zipping a <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> and a <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span></code>, we changed the first range to be a <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span></code>, what happens? We have a value type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code> and a reference type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>, similar to before. But now, neither is convertible to the other.</p>
<p>The constructor overload set of <code class="sourceCode cpp">std<span class="op">::</span>tuple</code> is… intense to say the least. But the relevant ones are:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode numberSource cpp numberLines"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">()</span>;</span>
<span id="cb15-2"><a href="#cb15-2"></a><span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span><span class="kw">const</span> Types<span class="op">&amp;...)</span>;         <span class="co">// only if sizeof...(Types) &gt;= 1</span></span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> UTypes<span class="op">&gt;</span></span>
<span id="cb15-4"><a href="#cb15-4"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span>UTypes<span class="op">&amp;&amp;...)</span>;           <span class="co">// only if sizeof...(Types) &gt;= 1</span></span>
<span id="cb15-5"><a href="#cb15-5"></a></span>
<span id="cb15-6"><a href="#cb15-6"></a>tuple<span class="op">(</span><span class="kw">const</span> tuple<span class="op">&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb15-7"><a href="#cb15-7"></a>tuple<span class="op">(</span>tuple<span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb15-8"><a href="#cb15-8"></a></span>
<span id="cb15-9"><a href="#cb15-9"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> UTypes<span class="op">&gt;</span></span>
<span id="cb15-10"><a href="#cb15-10"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span><span class="kw">const</span> tuple<span class="op">&lt;</span>UTypes<span class="op">...&gt;&amp;)</span>;</span>
<span id="cb15-11"><a href="#cb15-11"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> UTypes<span class="op">&gt;</span></span>
<span id="cb15-12"><a href="#cb15-12"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span>tuple<span class="op">&lt;</span>UTypes<span class="op">...&gt;&amp;&amp;)</span>;</span>
<span id="cb15-13"><a href="#cb15-13"></a></span>
<span id="cb15-14"><a href="#cb15-14"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> U1, <span class="kw">class</span> U2<span class="op">&gt;</span></span>
<span id="cb15-15"><a href="#cb15-15"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span><span class="kw">const</span> pair<span class="op">&lt;</span>U1, U2<span class="op">&gt;&amp;)</span>;   <span class="co">// only if sizeof...(Types) == 2</span></span>
<span id="cb15-16"><a href="#cb15-16"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> U1, <span class="kw">class</span> U2<span class="op">&gt;</span></span>
<span id="cb15-17"><a href="#cb15-17"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>see below</em><span class="op">)</span> tuple<span class="op">(</span>pair<span class="op">&lt;</span>U1, U2<span class="op">&gt;&amp;&amp;)</span>;        <span class="co">// only if sizeof...(Types) == 2</span></span></code></pre></div>
<p>We have a converting constructor from <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>U<span class="op">...&gt;</span> <span class="kw">const</span><span class="op">&amp;</span></code>, viable if <code class="sourceCode cpp"><span class="op">(</span>constructible_from<span class="op">&lt;</span>T, U <span class="kw">const</span><span class="op">&amp;&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code>, and a converting constructor <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>U<span class="op">...&gt;&amp;&amp;</span></code>, viable if <code class="sourceCode cpp"><span class="op">(</span>constructible_from<span class="op">&lt;</span>T, U<span class="op">&amp;&amp;&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">...)</span></code>. In both cases, we’re just distributing the qualifiers.</p>
<p>When trying to construct a <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code> from a <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>, we reject the converting constructor of lines 9-10 because we can’t construct a <code class="sourceCode cpp">std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> from a <code class="sourceCode cpp">std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span></code>. <code class="sourceCode cpp">std<span class="op">::</span>unique_ptr</code> isn’t copyable, and that’s not going to change.</p>
<p>When trying to construct a <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code> from an <em>lvalue</em> <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code> (the fact that it’s an lvalue is important), we reject that very same converting constructor because we can’t construct a <code class="sourceCode cpp">std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span></code> from a <code class="sourceCode cpp">std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span></code>. Can’t bind a non-const lvalue reference to a const lvalue. But we can of course bind a non-const lvalue reference to a non-const lvalue.</p>
<p>And indeed that’s how close this is to working. All we need is one more constructor (although we added two here for completeness):</p>
<div>
<div class="sourceCode" id="cb16"><pre class="sourceCode numberSource diff numberLines"><code class="sourceCode diff"><span id="cb16-1"><a href="#cb16-1"></a>  constexpr explicit(<em>see below</em>) tuple();</span>
<span id="cb16-2"><a href="#cb16-2"></a>  constexpr explicit(<em>see below</em>) tuple(const Types&amp;...);         // only if sizeof...(Types) &gt;= 1</span>
<span id="cb16-3"><a href="#cb16-3"></a>  template&lt;class... UTypes&gt;</span>
<span id="cb16-4"><a href="#cb16-4"></a>    constexpr explicit(<em>see below</em>) tuple(UTypes&amp;&amp;...);           // only if sizeof...(Types) &gt;= 1</span>
<span id="cb16-5"><a href="#cb16-5"></a></span>
<span id="cb16-6"><a href="#cb16-6"></a>  tuple(const tuple&amp;) = default;</span>
<span id="cb16-7"><a href="#cb16-7"></a>  tuple(tuple&amp;&amp;) = default;</span>
<span id="cb16-8"><a href="#cb16-8"></a></span>
<span id="cb16-9"><a href="#cb16-9"></a><span class="va">+ template&lt;class... UTypes&gt;</span></span>
<span id="cb16-10"><a href="#cb16-10"></a><span class="va">+   constexpr explicit(<em>see below</em>) tuple(tuple&lt;UTypes...&gt;&amp;);</span></span>
<span id="cb16-11"><a href="#cb16-11"></a>  template&lt;class... UTypes&gt;</span>
<span id="cb16-12"><a href="#cb16-12"></a>    constexpr explicit(<em>see below</em>) tuple(const tuple&lt;UTypes...&gt;&amp;);</span>
<span id="cb16-13"><a href="#cb16-13"></a>  template&lt;class... UTypes&gt;</span>
<span id="cb16-14"><a href="#cb16-14"></a>    constexpr explicit(<em>see below</em>) tuple(tuple&lt;UTypes...&gt;&amp;&amp;);</span>
<span id="cb16-15"><a href="#cb16-15"></a><span class="va">+ template&lt;class... UTypes&gt;</span></span>
<span id="cb16-16"><a href="#cb16-16"></a><span class="va">+   constexpr explicit(<em>see below</em>) tuple(const tuple&lt;UTypes...&gt;&amp;&amp;);  </span></span>
<span id="cb16-17"><a href="#cb16-17"></a></span>
<span id="cb16-18"><a href="#cb16-18"></a>  template&lt;class U1, class U2&gt;</span>
<span id="cb16-19"><a href="#cb16-19"></a>    constexpr explicit(<em>see below</em>) tuple(const pair&lt;U1, U2&gt;&amp;);   // only if sizeof...(Types) == 2</span>
<span id="cb16-20"><a href="#cb16-20"></a>  template&lt;class U1, class U2&gt;</span>
<span id="cb16-21"><a href="#cb16-21"></a>    constexpr explicit(<em>see below</em>) tuple(pair&lt;U1, U2&gt;&amp;&amp;);        // only if sizeof...(Types) == 2</span></code></pre></div>
</div>
<p>If only we had a way to express “a forwarding reference to <code class="sourceCode cpp">tuple<span class="op">&lt;</span>UTypes<span class="op">...&gt;</span></code>” in the language. But if we add these constructors, then suddenly we <em>can</em> construct a <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code> from an lvalue <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>std<span class="op">::</span>unique_ptr<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code>. And that would just end up binding the references as you would expect.</p>
<p>Such a change to the constructor set of <code class="sourceCode cpp">std<span class="op">::</span>tuple</code> means that all of our <code class="sourceCode cpp">zip_view</code> iterators can actually be <code class="sourceCode cpp">indirectly_readable</code>, which means they can actually count as being iterators. In all cases then, the common reference type of zip iterators would become the reference type. Indeed, this even fixes the issue we mentioned earlier - where even when our underlying types were copyable, we originally ended up with a common reference type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code>, a type that does not have reference semantics. But now it would have a common reference type of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>, which certainly has reference semantics.</p>
<p>We therefore propose that to extend the constructor overload set of <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>T<span class="op">...&gt;</span></code> to add converting constructors from <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>U<span class="op">...&gt;&amp;</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>U<span class="op">...&gt;</span> <span class="kw">const</span><span class="op">&amp;&amp;</span></code>. And likewise for <code class="sourceCode cpp">std<span class="op">::</span>pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>, for consistency.</p>
<h3 data-number="4.2.3" id="zip-and-zip_transforms-value_type"><span class="header-section-number">4.2.3</span> <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">zip_transform</code>’s <code class="sourceCode cpp">value_type</code><a href="#zip-and-zip_transforms-value_type" class="self-link"></a></h3>
<p>Returning to our favorite example again:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> vi <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb17-2"><a href="#cb17-2"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> vs <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb17-3"><a href="#cb17-3"></a></span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="kw">auto</span> a <span class="op">=</span> views<span class="op">::</span>zip<span class="op">(</span>vi, vs<span class="op">)</span>;</span></code></pre></div>
<p>Let’s talk about <code class="sourceCode cpp">a</code>. The reference type of <code class="sourceCode cpp">a</code> is <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>. That’s really the only option, it’s the whole point of <code class="sourceCode cpp">zip</code>. <code class="sourceCode cpp">range_reference_t<span class="op">&lt;</span>zip_view<span class="op">&lt;</span>R<span class="op">...&gt;&gt;</span></code> needs to be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code>.</p>
<p>But what’s the <code class="sourceCode cpp">value_type</code> of <code class="sourceCode cpp">a</code>? We ideally want the <code class="sourceCode cpp">value_type</code> to be something without reference semantics, something that we can properly hold onto and have a real copy. For a lot of ranges, the <code class="sourceCode cpp">reference</code> type is some <code class="sourceCode cpp">T<span class="op">&amp;</span></code> or <code class="sourceCode cpp">T <span class="kw">const</span><span class="op">&amp;</span></code> and so the <code class="sourceCode cpp">value_type</code> is just <code class="sourceCode cpp">T</code>. But here, our <code class="sourceCode cpp">reference</code> is a prvalue. So we have a choice.</p>
<p>We could do <code class="sourceCode cpp">std<span class="op">::</span>remove_cvref_t</code> on the <code class="sourceCode cpp">reference</code> as usual, that would give us just <code class="sourceCode cpp">reference</code> back, so the <code class="sourceCode cpp">value_type</code> of <code class="sourceCode cpp">a</code> would be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>. Not really an independent, value type.</p>
<p>Or, since we know what <code class="sourceCode cpp">zip</code> is, we don’t have to guess what a good <code class="sourceCode cpp">value_type</code> might be. We could use the ranges themselves to tell us what that is. Each constituent <code class="sourceCode cpp">R</code> already provides a <code class="sourceCode cpp">range_value_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code>, and if those choices are good enough for the <code class="sourceCode cpp">R</code>s, they should be good enough for <code class="sourceCode cpp">zip</code>. That is, <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_value_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code>. Which, for <code class="sourceCode cpp">a</code>, would be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span>, std<span class="op">::</span>string<span class="op">&gt;</span></code>.</p>
<p>But there’s a wrinkle here, consider:</p>
<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">auto</span> b <span class="op">=</span> views<span class="op">::</span>zip_transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;...</span> r<span class="op">){</span></span>
<span id="cb18-2"><a href="#cb18-2"></a>    <span class="cf">return</span> std<span class="op">::</span>tie<span class="op">(</span>r<span class="op">...)</span>;</span>
<span id="cb18-3"><a href="#cb18-3"></a><span class="op">}</span>, vi, vs<span class="op">)</span>;</span></code></pre></div>
<p>The <code class="sourceCode cpp">reference</code> type of <code class="sourceCode cpp">b</code> is necessarily determined by the callable here: <code class="sourceCode cpp">invoke_result_t<span class="op">&lt;</span>F<span class="op">&amp;</span>, range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code>. In this case, this gives us <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>. Notably, this is exactly the same <code class="sourceCode cpp">reference</code> type as with saw with <code class="sourceCode cpp">a</code>.</p>
<p>But what’s the <code class="sourceCode cpp">value_type</code> of <code class="sourceCode cpp">b</code>? Unlike in the case of <code class="sourceCode cpp">zip</code>, with <code class="sourceCode cpp">zip_transform</code> we really have no idea where the <code class="sourceCode cpp">reference</code> type came from. It need not be any kind of reference at all, it could be… <code class="sourceCode cpp"><span class="dt">int</span></code>. For <code class="sourceCode cpp">zip_transform</code>, we really can’t do much better than <code class="sourceCode cpp">remove_cvref_t<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>F<span class="op">&amp;</span>, range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;&gt;</span></code> — which again gets us back to the same <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code>.</p>
<p>A hypothetical different direction would be to introduce a type trait that would inform range adapters how to turn a reference-semantic type to a value type. Something that would turn <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code> into <code class="sourceCode cpp"><span class="dt">bool</span></code>, or <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>T<span class="op">&amp;...&gt;</span></code> into <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>T<span class="op">...&gt;</span></code>. Then other range adapters could have used it themselves.</p>
<p>But <code class="sourceCode cpp">views<span class="op">::</span>transform</code> already exists, and is very similar in nature to <code class="sourceCode cpp">views<span class="op">::</span>zip_transform</code>. Indeed, <code class="sourceCode cpp">views<span class="op">::</span>zip_transform<span class="op">(</span>F, E<span class="op">...)</span></code> is very nearly <code class="sourceCode cpp">views<span class="op">::</span>zip<span class="op">(</span>E<span class="op">...)</span> <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([=](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> tup<span class="op">){</span> <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">(</span>F, std<span class="op">::</span>forward<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>tup<span class="op">)&gt;(</span>tup<span class="op">))</span>; <span class="op">})</span></code>, so any attempt to make <code class="sourceCode cpp">zip_transform</code>’s <code class="sourceCode cpp">value_type</code> line up with <code class="sourceCode cpp">zip</code>’s would mean changing the existing behavior of <code class="sourceCode cpp">views<span class="op">::</span>transform</code>. That makes it unviable to pursue (assuming it were even a good idea to begin with).</p>
<p>The other way to get <code class="sourceCode cpp">zip_transform</code>’s <code class="sourceCode cpp">value_type</code> to be consistent with <code class="sourceCode cpp">zip</code>’s is to abandon the aforementioned symmetry and just use <code class="sourceCode cpp">remove_cvref_t</code> to determine <code class="sourceCode cpp">zip</code>’s <code class="sourceCode cpp">value_type</code> as well. But we find this questionable — we shouldn’t sacrifice <code class="sourceCode cpp">zip</code> at the altar of consistency. It’s really not that big of a deal, it’s an inconsistency that only really surfaces when users would use <code class="sourceCode cpp">zip_transform</code> to do exactly what <code class="sourceCode cpp">zip</code> already does. But why would they do that, when they have <code class="sourceCode cpp">zip</code>?</p>
<p>In short, we propose that:</p>
<table>
<colgroup>
<col style="width: 33%"></col>
<col style="width: 33%"></col>
<col style="width: 33%"></col>
</colgroup>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">reference</code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">value_type</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">zip_view<span class="op">&lt;</span>R<span class="op">...&gt;</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span>range_value_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">zip_transform_view<span class="op">&lt;</span>F, R<span class="op">...&gt;</span></code></td>
<td><code class="sourceCode cpp">invoke_result_t<span class="op">&lt;</span>F<span class="op">&amp;</span>, range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;</span></code></td>
<td><code class="sourceCode cpp">remove_cvref_t<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>F<span class="op">&amp;</span>, range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;...&gt;&gt;</span></code></td>
</tr>
</tbody>
</table>
<p>Or for this specific example:</p>
<table>
<colgroup>
<col style="width: 33%"></col>
<col style="width: 33%"></col>
<col style="width: 33%"></col>
</colgroup>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">reference</code></strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">value_type</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">a</code> —<code class="sourceCode cpp">zip<span class="op">(</span>vi, vs<span class="op">)</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span>, std<span class="op">::</span>string</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">b</code> — <code class="sourceCode cpp">zip_transform<span class="op">(</span><em>std::tie</em>, vi, vs<span class="op">)</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;</span>, std<span class="op">::</span>string<span class="op">&amp;&gt;</span></code></td>
</tr>
</tbody>
</table>
<p>We think these would be the most valuable choices.</p>
<h3 data-number="4.2.4" id="enumerates-first-range"><span class="header-section-number">4.2.4</span> <code class="sourceCode cpp">enumerate</code>’s first range<a href="#enumerates-first-range" class="self-link"></a></h3>
<p>We wrote earlier that <code class="sourceCode cpp">enumerate<span class="op">(</span>r<span class="op">)</span></code> can be defined as <code class="sourceCode cpp">zip<span class="op">(</span>iota<span class="op">(</span>range_size_t<span class="op">&lt;</span>R<span class="op">&gt;(</span><span class="dv">0</span><span class="op">))</span>, r<span class="op">)</span></code>, but it turns out that this isn’t <em>quite</em> right, and we need to do something slightly different.</p>
<p>It turns out <code class="sourceCode cpp">iota</code> is a fairly complicated view due to wanting to avoid undefined behavior in its <code class="sourceCode cpp">difference_type</code> <span class="citation" data-cites="P1522R1">[<a href="#ref-P1522R1" role="doc-biblioref">P1522R1</a>]</span>. <code class="sourceCode cpp">iota_view</code> has to choose a type that is wide enough to properly compute differences. One of the important points in that paper is that integer-like types are:</p>
<div class="quote">
<p>Not required to be <code class="sourceCode cpp">WeaklyIncrementable</code>: There is no requirement that a user-defined integer-like type specify what <em>its</em> difference type is. (If we were to require that, then by induction implementors would be on the hook to provide an infinite-precision integer-like type.) Therefore, <code class="sourceCode cpp">iota_view<span class="op">&lt;</span>iter_difference_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span></code> for an arbitrary iterator <code class="sourceCode cpp">I</code> may in fact be ill-formed.</p>
</div>
<p>Similarly, <code class="sourceCode cpp">iota<span class="op">(</span>range_size_t<span class="op">&lt;</span>R<span class="op">&gt;(</span><span class="dv">0</span><span class="op">))</span></code> need not be valid <span class="citation" data-cites="range-v3.1141">[<a href="#ref-range-v3.1141" role="doc-biblioref">range-v3.1141</a>]</span>. And, even if it were valid, it may be a wider integer type than would be strictly necessary. But <code class="sourceCode cpp">enumerate</code> is not as general-purpose as <code class="sourceCode cpp">iota</code>. From Eric Niebler:</p>
<div class="quote">
<p>However, the enumerate view is special. The <code class="sourceCode cpp">iota_view<span class="op">&lt;</span>diffmax_t<span class="op">&gt;</span></code> that <code class="sourceCode cpp">view<span class="op">::</span>enumerate</code> constructs will never produce a number less than zero or greater than the maximum <code class="sourceCode cpp">diffmax_t</code>. So <code class="sourceCode cpp">diffmax_t</code> itself has enough bits to be usable as the difference type of <code class="sourceCode cpp">iota_view<span class="op">&lt;</span>diffmax_t<span class="op">&gt;::</span>iterator</code>.</p>
<p>I can solve this problem with a custom <code class="sourceCode cpp">index_view</code> that doesn’t try to promote the index type when computing the difference type.</p>
</div>
<p>And this is what range-v3 does: <code class="sourceCode cpp">enumerate<span class="op">(</span>r<span class="op">)</span></code> is defined as <code class="sourceCode cpp">zip<span class="op">(</span><em>index-view</em><span class="op">&lt;</span>range_size_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, range_difference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;()</span>, r<span class="op">)</span></code>, where <code class="sourceCode cpp"><em>index-view</em><span class="op">&lt;</span>S, D<span class="op">&gt;</span></code> is basically a specialized version of <code class="sourceCode cpp">iota</code> such that <code class="sourceCode cpp">range_size_t<span class="op">&lt;</span><em>index-view</em><span class="op">&lt;</span>S, D<span class="op">&gt;&gt;</span></code> is <code class="sourceCode cpp">S</code> and <code class="sourceCode cpp">range_difference_t<span class="op">&lt;</span><em>index-view</em><span class="op">&lt;</span>S, D<span class="op">&gt;&gt;</span></code> is <code class="sourceCode cpp">D</code>. That is, rather than trying to compute a size and difference types to fit the range, we just use the provided range’s size and difference types. If it’s good enough for <code class="sourceCode cpp">R</code>, it’s good enough for <code class="sourceCode cpp">enumerate_view<span class="op">&lt;</span>R<span class="op">&gt;</span></code>!</p>
<p>This <code class="sourceCode cpp"><em>index-view</em></code> can be exposition-only, it’s effectively an implementation detail of <code class="sourceCode cpp">enumerate</code>.</p>
<h3 data-number="4.2.5" id="does-adjacent-mean-2-or-n"><span class="header-section-number">4.2.5</span> Does <code class="sourceCode cpp">adjacent</code> mean <code class="sourceCode cpp"><span class="dv">2</span></code> or <code class="sourceCode cpp">n</code>?<a href="#does-adjacent-mean-2-or-n" class="self-link"></a></h3>
<p>In C++20, we have the range adapters <code class="sourceCode cpp">keys</code> and <code class="sourceCode cpp">values</code> which are actually specified as <code class="sourceCode cpp">elements<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;</span></code> and <code class="sourceCode cpp">elements<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span></code>, respectively, where <code class="sourceCode cpp">elements<span class="op">&lt;</span>N<span class="op">&gt;</span></code> is a generic range adapter that picks the <code class="sourceCode cpp">N</code>th part from a range of tuples.</p>
<p>Now consider <code class="sourceCode cpp">adjacent</code>. This view could simply mean to take elements two-at-a-time, taking a range of <code class="sourceCode cpp">T</code> and producing a range of <code class="sourceCode cpp"><span class="op">(</span>T, T<span class="op">)</span></code> (as a tuple). But there isn’t anything particularly special about two, just that it’d probably be the most used value. There’s not much additional specification effort to create a range adapter that takes elements n-at-a-time and produces a range of n-tuple. In that case, we could specify <code class="sourceCode cpp">adjacent</code> as <code class="sourceCode cpp">slide_as_tuple<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span></code> (this closely resembles the algorithm <code class="sourceCode cpp">slide</code> described <a href="#the-sliding-family">later</a>, the difference being that here we need the value as a constant expression to produce a range of tuples, while there we produce a range of ranges). Alternatively, <code class="sourceCode cpp">adjacent</code> itself could be the generic algorithm and we could introduce a specialized name to mean <code class="sourceCode cpp">adjacent<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span></code>. For instance, Python calls this <code class="sourceCode cpp">pairwise</code> and Kotlin calls it <code class="sourceCode cpp">zipWithNext</code>.</p>
<h2 data-number="4.3" id="the-group_by-family"><span class="header-section-number">4.3</span> The <code class="sourceCode cpp">group_by</code> family<a href="#the-group_by-family" class="self-link"></a></h2>
<p>This family, as the name suggests, take a range of <code class="sourceCode cpp">T</code> and groups them based on some provided function function. <code class="sourceCode cpp">group_by</code> is one of the most consistently named algorithms across all languages (modulo choice of spelling, as in <code class="sourceCode cpp">groupBy</code> or <code class="sourceCode cpp">group<span class="op">-</span>by</code>) yet there are actually three-ish different approaches to what this algorithm actually means:</p>
<ol type="1">
<li>Take a binary predicate, <code class="sourceCode cpp"><span class="op">(</span>T, T<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span></code>, and invoke this predicate on consecutive elements and start a new group when that predicate returns <code class="sourceCode cpp"><span class="kw">false</span></code>. Using Haskell notation, we’re taking a <code class="sourceCode cpp"><span class="op">[</span>T<span class="op">]</span></code> (range of <code class="sourceCode cpp">T</code>) and producing a <code class="sourceCode cpp"><span class="op">[[</span><span class="at">T</span><span class="op">]]</span></code> (range of range of <code class="sourceCode cpp">T</code>).</li>
<li>Take a unary function, <code class="sourceCode cpp">T <span class="op">-&gt;</span> U</code> (such that <code class="sourceCode cpp">U</code> models <code class="sourceCode cpp">equality_comparable</code>), and group consecutive elements with the same <code class="sourceCode cpp">U</code>. Following the law of useful return, these algorithms don’t just give you a <code class="sourceCode cpp"><span class="op">[[</span><span class="at">T</span><span class="op">]]</span></code> back, they rather give you a <code class="sourceCode cpp"><span class="op">[(</span>U, <span class="op">[</span>T<span class="op">])]</span></code> — the algorithm had to compute the <code class="sourceCode cpp">U</code>s for each element so they should give it to the user.</li>
<li>Take a unary function, <code class="sourceCode cpp">T <span class="op">-&gt;</span> U</code>, and return a dictionary that maps every <code class="sourceCode cpp">U</code> to a list of <code class="sourceCode cpp">T</code>s that mapped to it.</li>
</ol>
<p>Haskell, Elixir, D (<code class="sourceCode cpp">chunkBy</code>), and range-v3 (~ish) provide the first kind. Rust, Python, D (also <code class="sourceCode cpp">chunkBy</code> — it allows both uses), and F# provide the second. Clojure, Kotlin, and Scala provide the third.</p>
<p>Swift recently announced its own set of algorithms <span class="citation" data-cites="swift.algorithms">[<a href="#ref-swift.algorithms" role="doc-biblioref">swift.algorithms</a>]</span>. It provides the first kind as <code class="sourceCode cpp">chunked<span class="op">(</span>by<span class="op">:</span> f<span class="op">)</span></code> and the second kind as <code class="sourceCode cpp">chunked<span class="op">(</span>on<span class="op">:</span> f<span class="op">)</span></code> (Swift allows overloading based on named function arguments).</p>
<p>range-v3 is mostly in the first category, except its implementation choice is quite different from the other languages. It always compares the <em>first</em> element in each subrange with each subsequent one, while the others always compare <em>consecutive</em> elements. As such, they may yield very different results:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb1-1"><a href="#cb1-1"></a><span class="op">&gt;&gt;&gt;</span> groupBy (<span class="op">&lt;=</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">2</span>]</span>
<span id="cb1-2"><a href="#cb1-2"></a>[[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">1</span>,<span class="dv">2</span>],[<span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">5</span>],[<span class="dv">2</span>]] <span class="co">-- Haskell&#39;s implementation</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>[[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">1</span>,<span class="dv">2</span>],[<span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">2</span>]]     <span class="co">-- range-v3&#39;s implementation</span></span></code></pre></div>
<p>In Haskell, the second <code class="sourceCode cpp"><span class="dv">1</span></code> starts a new group because we’re comparing it with its previous element and <code class="sourceCode cpp"><span class="dv">3</span> <span class="op">&lt;=</span> <span class="dv">1</span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>. But in range-v3, the second <code class="sourceCode cpp"><span class="dv">1</span></code> does not start a new group because we’re comparing it with the first element of the group, and <code class="sourceCode cpp"><span class="dv">1</span> <span class="op">&lt;=</span> <span class="dv">1</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. We think the Haskell/Elixir/D choice is more familiar and more useful.</p>
<p>It’s also worth noting that technically Haskell has <em>two</em> different <code class="sourceCode cpp">groupBy</code> functions: <code class="sourceCode cpp">Data<span class="op">.</span>List<span class="op">.</span>groupBy</code> (which does what range-v3 does) and <code class="sourceCode cpp">Data<span class="op">.</span>List<span class="op">.</span>GroupBy<span class="op">.</span>groupBy</code> (which does what we’re stating Haskell’s implementation really is). This newer one is even called the “Replacement definition” in its docs <span class="citation" data-cites="haskell.groupby">[<a href="#ref-haskell.groupby" role="doc-biblioref">haskell.groupby</a>]</span>.</p>
<p>The question is <em>which</em> one of the three options would we want to pick for C++Next?</p>
<p>Well, when it comes to algorithms, the more the better. We think it’s clear we wouldn’t want to pick the 3rd option (we can easily produce a dictionary from the 2nd option), so the question is between the first two. While the binary version of <code class="sourceCode cpp">group_by</code> is more generic (since you approximate the unary version in terms of it, even it’s a different shape) and thus more broadly applicable, the unary version also comes up frequently and as such we feel that we should provide both.</p>
<p>We could hypothetically follow the D model and provide both under the same name, selecting based on whether the provided callable is a unary invocable or a binary predicate — but we’re not sure if that’s the best idea.</p>
<p>Given the time and bandwidth pressure, we think the top priority is the binary <code class="sourceCode cpp">group_by</code> and the unary form, while still very useful, should be a Tier 2 addition.</p>
<p>As far as naming goes, our preferred naming is:</p>
<ul>
<li><code class="sourceCode cpp">chunk_by</code> takes a binary predicate</li>
<li><code class="sourceCode cpp">chunk_on</code> (or perhaps <code class="sourceCode cpp">chunk_by_key</code> or <code class="sourceCode cpp">chunk_on_key</code>) takes a unary transform and produces a range of pairs (as D, Rust, and Python do, but Swift does not)</li>
</ul>
<p>This would give us three range adaptors that produce non-overlapping ranges of ranges that include every element of the original range exactly once:</p>
<ul>
<li><code class="sourceCode cpp">chunk</code>, which takes a number (described <a href="#the-sliding-family">here</a>)</li>
<li><code class="sourceCode cpp">chunk_by</code>, which takes a binary predicate</li>
<li><code class="sourceCode cpp">chunk_on</code> (or whatever), which takes a unary projection</li>
</ul>
<p>And we think that it’s nice that all of these algorithms have the same root. There <em>are</em> other algorithms that produces ranges of ranges, but they either exclude some elements (<code class="sourceCode cpp">split</code>) or repeat some elements (<code class="sourceCode cpp">slide</code>).</p>
<p>Additionally, just recently, range-v3 just added a <a href="https://github.com/ericniebler/range-v3/pull/1648"><code class="sourceCode cpp">views<span class="op">::</span>chunk_by</code></a> that does exactly as suggested here (comparing consecutive elements, as opposed to range-v3 preexisting <code class="sourceCode cpp">views<span class="op">::</span>group_by</code> which compares against the first in group).</p>
<p>This is proposed in <span class="citation" data-cites="P2443R0">[<a href="#ref-P2443R0" role="doc-biblioref">P2443R0</a>]</span>.</p>
<h2 data-number="4.4" id="monadic-binds"><span class="header-section-number">4.4</span> Monadic binds<a href="#monadic-binds" class="self-link"></a></h2>
<p>We added <code class="sourceCode cpp">views<span class="op">::</span>transform</code> in C++20, but there are closely related views in that family, which several other languages also provide.</p>
<p><code class="sourceCode cpp">views<span class="op">::</span>transform</code> takes a range of <code class="sourceCode cpp">T</code> and a function <code class="sourceCode cpp">T <span class="op">-&gt;</span> U</code> and produces a range of <code class="sourceCode cpp">U</code>. But we can play around with the shape of the callable to produce two other extremely useful adapters:</p>
<ul>
<li>we can take a function <code class="sourceCode cpp">T <span class="op">-&gt;</span> RangeOf<span class="op">&lt;</span>U<span class="op">&gt;</span></code> and produce a range of <code class="sourceCode cpp">U</code>. That is, take the resulting range and flatten it out into a single range.</li>
<li>we can take a function <code class="sourceCode cpp">T <span class="op">-&gt;</span> optional<span class="op">&lt;</span>U<span class="op">&gt;</span></code> and produce a range of <code class="sourceCode cpp">U</code> from those resulting optionals that are engaged.</li>
</ul>
<p>The former is commonly known as <code class="sourceCode cpp">flat_map</code> (because it’s a <code class="sourceCode cpp">map</code> followed by a <code class="sourceCode cpp">flatten</code>), although C++20’s version of <code class="sourceCode cpp">flatten</code> is named <code class="sourceCode cpp">join</code> and C++20’s version of <code class="sourceCode cpp">map</code> is named <code class="sourceCode cpp">transform</code>. So perhaps this adapter should be named <code class="sourceCode cpp">join_transform</code> or <code class="sourceCode cpp">transform_join</code>? Eughh?</p>
<p>The latter is called <code class="sourceCode cpp">filter_map</code> in Rust and <code class="sourceCode cpp">compactMap</code> in Swift. Neither strike us as great names either. A Haskell package calls this <code class="sourceCode cpp">mapMaybe</code> which informs our proposed name: <code class="sourceCode cpp">transform_maybe</code>.</p>
<p>There really aren’t any particular thorny library issues to resolve here, simply a question of specification.</p>
<h3 data-number="4.4.1" id="flat_map"><span class="header-section-number">4.4.1</span> <code class="sourceCode cpp">flat_map</code><a href="#flat_map" class="self-link"></a></h3>
<p><code class="sourceCode cpp">flat_map<span class="op">(</span>E, F<span class="op">)</span></code> is, following the adoption of <span class="citation" data-cites="P2328R1">[<a href="#ref-P2328R1" role="doc-biblioref">P2328R1</a>]</span>, exactly <code class="sourceCode cpp">join<span class="op">(</span>transform<span class="op">(</span>E, F<span class="op">))</span></code>.</p>
<p>Prior to that paper, it used to be the case that if the callable returned a prvalue range that is not a <code class="sourceCode cpp">view</code> (a seemingly specific constraint that is actually a very common use-case - consider a function returning a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code>), then the <code class="sourceCode cpp">join</code> would fail. The workaround for this was a range adaptor in range-v3 called <code class="sourceCode cpp">cache1</code>, but that adaptor has other design issues (described in the above paper) and as a result is not considered a high priority right now.</p>
<p>Given that, we could specify <code class="sourceCode cpp">views<span class="op">::</span>flat_map<span class="op">(</span>E, F<span class="op">)</span></code> as expression-equivalent to <code class="sourceCode cpp">views<span class="op">::</span>join<span class="op">(</span>views<span class="op">::</span>transform<span class="op">(</span>E, F<span class="op">))</span></code>. It’s not clear that there is a more efficient way to implement this (unlike the case of, say, <code class="sourceCode cpp">views<span class="op">::</span>tail</code> vs <code class="sourceCode cpp">views<span class="op">::</span>drop<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code> described earlier), so we could add this as a trivial alias. We don’t have examples of aliases like this in the standard library today (<code class="sourceCode cpp">keys</code> is an alias for <code class="sourceCode cpp">elements<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;</span></code>, but that’s still a single adaptor).</p>
<h3 data-number="4.4.2" id="transform_maybe"><span class="header-section-number">4.4.2</span> <code class="sourceCode cpp">transform_maybe</code><a href="#transform_maybe" class="self-link"></a></h3>
<p>For <code class="sourceCode cpp">transform_maybe</code>, <span class="citation" data-cites="P1255R6">[<a href="#ref-P1255R6" role="doc-biblioref">P1255R6</a>]</span> seeks to address this problem but requires using three chained adapters:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> transform_maybe1 <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> f<span class="op">){</span></span>
<span id="cb19-2"><a href="#cb19-2"></a>    <span class="cf">return</span> views<span class="op">::</span>transform<span class="op">(</span>FWD<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>views<span class="op">::</span>maybe<span class="op">)</span></span>
<span id="cb19-4"><a href="#cb19-4"></a>         <span class="op">|</span> views<span class="op">::</span>join;</span>
<span id="cb19-5"><a href="#cb19-5"></a><span class="op">}</span>;</span></code></pre></div>
<p>This is an expensive implementation. Not only do we need three adapters, but <code class="sourceCode cpp">join</code> is a very complex adapter and we have an extremely specialized case here that is much simpler. Moreover, the result of <code class="sourceCode cpp">transform_maybe1</code> is always an input range only (we are joining a range of prvalue ranges).</p>
<p>We could get the same behavior out of three simpler adapters in a different way in C++20:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> transform_maybe2 <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> f<span class="op">){</span></span>
<span id="cb20-2"><a href="#cb20-2"></a>    <span class="cf">return</span> views<span class="op">::</span>transform<span class="op">(</span>FWD<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb20-3"><a href="#cb20-3"></a>         <span class="op">|</span> views<span class="op">::</span>filter<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">))</span> <span class="op">{</span></span>
<span id="cb20-4"><a href="#cb20-4"></a>               <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">)</span>;</span>
<span id="cb20-5"><a href="#cb20-5"></a>           <span class="op">})</span></span>
<span id="cb20-6"><a href="#cb20-6"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><em>decay-copy</em><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">)))</span> <span class="op">{</span></span>
<span id="cb20-7"><a href="#cb20-7"></a>               <span class="cf">return</span> <em>decay-copy</em><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb20-8"><a href="#cb20-8"></a>           <span class="op">})</span>;</span>
<span id="cb20-9"><a href="#cb20-9"></a><span class="op">}</span>;</span></code></pre></div>
<p>This implementation can now potentially be a bidirectional range (instead of <code class="sourceCode cpp">input</code>-only) thanks to avoiding <code class="sourceCode cpp">join</code>, but it still uses three adapters.</p>
<p>Both of these implementations have the issue of doing unnecessary extra copies. Let’s say we have a range of <code class="sourceCode cpp">T</code> and a bunch of example functions, what would we want the resulting <code class="sourceCode cpp">filter_map</code>’s reference type to be?</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>function</strong>
</div></th>
<th><div style="text-align:center">
<strong>desired reference type</strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">maybe</code> result</strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">filter</code> result</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">T <span class="op">-&gt;</span> A<span class="op">*</span></code></td>
<td><code class="sourceCode cpp">A<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">A<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">A</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">T <span class="op">-&gt;</span> std<span class="op">::</span>optional<span class="op">&lt;</span>B<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">B <span class="kw">const</span><span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">B<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">B</code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">T <span class="op">-&gt;</span> std<span class="op">::</span>optional<span class="op">&lt;</span>C<span class="op">&gt;</span></code></td>
<td><code class="sourceCode cpp">C</code></td>
<td><code class="sourceCode cpp">C<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">C</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">T <span class="op">-&gt;</span> boost<span class="op">::</span>optional<span class="op">&lt;</span>D<span class="op">&amp;&gt;</span></code></td>
<td><code class="sourceCode cpp">D<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">D<span class="op">&amp;</span></code></td>
<td><code class="sourceCode cpp">D</code></td>
</tr>
</tbody>
</table>
<p>The <code class="sourceCode cpp">maybe</code> implementation always yields lvalue references, the <code class="sourceCode cpp">transform<span class="op">-</span>filter<span class="op">-</span>transform</code> implementation always yields prvalues. The latter is predictable - we always copy out - whereas the former doesn’t need to copy the <code class="sourceCode cpp">D</code>, although it does copy the <code class="sourceCode cpp">B</code> despite perhaps looking as if it does not (it does copy the <code class="sourceCode cpp">C</code>, and needs to, although it likewise might appear as if it does not).</p>
<p>We can provide the desired result with a more complex version of the final <code class="sourceCode cpp">transform</code> by only decaying xvalues:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> transform_maybe3 <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> f<span class="op">){</span></span>
<span id="cb21-2"><a href="#cb21-2"></a>    <span class="cf">return</span> views<span class="op">::</span>transform<span class="op">(</span>FWD<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb21-3"><a href="#cb21-3"></a>         <span class="op">|</span> views<span class="op">::</span>filter<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">))</span> <span class="op">{</span></span>
<span id="cb21-4"><a href="#cb21-4"></a>               <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">)</span>;</span>
<span id="cb21-5"><a href="#cb21-5"></a>           <span class="op">})</span></span>
<span id="cb21-6"><a href="#cb21-6"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> <span class="op">*</span>e; <span class="op">}</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-7"><a href="#cb21-7"></a>               <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_rvalue_reference_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">))&gt;)</span> <span class="op">{</span></span>
<span id="cb21-8"><a href="#cb21-8"></a>                   <span class="cf">return</span> <em>decay-copy</em><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb21-9"><a href="#cb21-9"></a>               <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb21-10"><a href="#cb21-10"></a>                   <span class="cf">return</span> <span class="op">*</span>FWD<span class="op">(</span>e<span class="op">)</span>;</span>
<span id="cb21-11"><a href="#cb21-11"></a>               <span class="op">}</span></span>
<span id="cb21-12"><a href="#cb21-12"></a>           <span class="op">})</span>;</span>
<span id="cb21-13"><a href="#cb21-13"></a><span class="op">}</span>;</span></code></pre></div>
<p>This is certainly quite a bit more complicated than the <code class="sourceCode cpp">views<span class="op">::</span>tail</code> implementation suggested earlier!</p>
<p>But we don’t want to specify it like that either. Even <code class="sourceCode cpp">transform3</code> has a huge problem: how many times do we invoke the callable? Ideally, if we’re just traversing the resulting range one time, we’d invoke the function one time per element in the input range. But that’s not actually the case here - we would have to end up invoking the function twice in the case that it yields an engaged <code class="sourceCode cpp">optional</code>. This follows directly from the underlying iterator model: the <code class="sourceCode cpp">transform_view</code>’s <code class="sourceCode cpp">iterator<span class="op">::</span><span class="kw">operator</span><span class="op">*</span></code> invokes the function, while <code class="sourceCode cpp">filter_view</code>’s <code class="sourceCode cpp">iterator<span class="op">::</span><span class="kw">operator</span><span class="op">++</span></code> does a <code class="sourceCode cpp">find_if</code>. For elements that are filtered in, there would be one dereference during the <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">++</span></code> to stop searching and then again to actually propagate the value in the <code class="sourceCode cpp">filter_view</code>’s <code class="sourceCode cpp">iterator<span class="op">::</span><span class="kw">operator</span><span class="op">*</span></code>. This could be resolved by adding yet another adapter that we already mentioned:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> transform_maybe4 <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> f<span class="op">){</span></span>
<span id="cb22-2"><a href="#cb22-2"></a>    <span class="cf">return</span> views<span class="op">::</span>transform<span class="op">(</span>FWD<span class="op">(</span>f<span class="op">))</span></span>
<span id="cb22-3"><a href="#cb22-3"></a>         <span class="op">|</span> views<span class="op">::</span>cache_latest</span>
<span id="cb22-4"><a href="#cb22-4"></a>         <span class="op">|</span> views<span class="op">::</span>filter<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">))</span> <span class="op">{</span></span>
<span id="cb22-5"><a href="#cb22-5"></a>               <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;(</span>e<span class="op">)</span>;</span>
<span id="cb22-6"><a href="#cb22-6"></a>           <span class="op">})</span></span>
<span id="cb22-7"><a href="#cb22-7"></a>         <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> <span class="op">*</span>e; <span class="op">}</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-8"><a href="#cb22-8"></a>               <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_rvalue_reference_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">))&gt;)</span> <span class="op">{</span></span>
<span id="cb22-9"><a href="#cb22-9"></a>                   <span class="cf">return</span> <em>decay-copy</em><span class="op">(*</span>FWD<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb22-10"><a href="#cb22-10"></a>               <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb22-11"><a href="#cb22-11"></a>                   <span class="cf">return</span> <span class="op">*</span>FWD<span class="op">(</span>e<span class="op">)</span>;</span>
<span id="cb22-12"><a href="#cb22-12"></a>               <span class="op">}</span></span>
<span id="cb22-13"><a href="#cb22-13"></a>           <span class="op">})</span>;</span>
<span id="cb22-14"><a href="#cb22-14"></a><span class="op">}</span>;</span></code></pre></div>
<p>We think that <code class="sourceCode cpp">transform_view</code> merits a first-class view to accomplish this functionality not only because the above is very involved but also because it still has unnecessary overhead - it’d be nice to avoid instantiating <em>four</em> views when one is sufficient, along with all the wrapping that entails.</p>
<p>However, because of the <code class="sourceCode cpp">cache_latest</code> dependency (see also <span class="citation" data-cites="P2328R1">[<a href="#ref-P2328R1" role="doc-biblioref">P2328R1</a>]</span>), we’re kicking this one down to Tier 2.</p>
<h2 data-number="4.5" id="the-sliding-family"><span class="header-section-number">4.5</span> The sliding family<a href="#the-sliding-family" class="self-link"></a></h2>
<p>Conor talks about this family of ranges in a CppCon 2019 lighting talk <span class="citation" data-cites="hoekstra.cppcon">[<a href="#ref-hoekstra.cppcon" role="doc-biblioref">hoekstra.cppcon</a>]</span>.</p>
<ul>
<li><code class="sourceCode cpp">chunk<span class="op">(</span>N<span class="op">)</span></code> breaks a range into non-overlapping ranges of length <code class="sourceCode cpp">N</code>. <code class="sourceCode cpp">views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>,<span class="dv">10</span><span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>chunk<span class="op">(</span><span class="dv">4</span><span class="op">)</span></code> yields <code class="sourceCode cpp"><span class="op">[[</span><span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span><span class="op">]</span>,<span class="op">[</span><span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span><span class="op">]</span>,<span class="op">[</span><span class="dv">8</span>,<span class="dv">9</span><span class="op">]]</span></code>. Note that the last range has length less than 4. See <span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span>.</li>
<li><code class="sourceCode cpp">slide<span class="op">(</span>N<span class="op">)</span></code> is very similar to <code class="sourceCode cpp">chunk</code> except its subranges are overlapping and all have length exactly <code class="sourceCode cpp">N</code>. <code class="sourceCode cpp">views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>,<span class="dv">10</span><span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>slide<span class="op">(</span><span class="dv">4</span><span class="op">)</span></code> yields <code class="sourceCode cpp"><span class="op">[[</span><span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span><span class="op">]</span>,<span class="op">[</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span><span class="op">]</span>,<span class="op">[</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span><span class="op">]</span>,<span class="op">[</span><span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span><span class="op">]</span>,<span class="op">[</span><span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span><span class="op">]</span>,<span class="op">[</span><span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span><span class="op">]</span>,<span class="op">[</span><span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span><span class="op">]]</span></code>. Note that <code class="sourceCode cpp">slide<span class="op">(</span><span class="dv">2</span><span class="op">)</span></code> is similar to <code class="sourceCode cpp">adjacent</code>, except that the latter yields a range of tuples (i.e. having compile-time size) whereas here we have a range of ranges (still having runtime size). range-v3 calls this <code class="sourceCode cpp">sliding</code>, which has a different tense from the other two, so we change it to <code class="sourceCode cpp">slide</code> here. See <span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span>.</li>
<li><code class="sourceCode cpp">stride<span class="op">(</span>N<span class="op">)</span></code> takes every <code class="sourceCode cpp">N</code>th element. <code class="sourceCode cpp">views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">10</span><span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>stride<span class="op">(</span><span class="dv">4</span><span class="op">)</span></code> yields <code class="sourceCode cpp"><span class="op">[</span><span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">8</span><span class="op">]</span></code>. Note that unlike the other two, this one is not a range of ranges, but still fits in with this family. See <span class="citation" data-cites="P1899R0">[<a href="#ref-P1899R0" role="doc-biblioref">P1899R0</a>]</span>.</li>
</ul>
<p>These are three specific examples of a general algorithm that takes three parameters: the size of the subranges to return, the size of the step to take after each subrange, and whether to include partial ranges. Kotlin calls this algorithm <code class="sourceCode cpp">windowed</code>, Scala calls it <code class="sourceCode cpp">sliding</code>, D calls it <code class="sourceCode cpp">slide</code>, Haskell calls it <code class="sourceCode cpp">divvy</code>, and Clojure calls it <code class="sourceCode cpp">partition</code>.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Algorithm</strong>
</div></th>
<th><div style="text-align:center">
<strong>Step</strong>
</div></th>
<th><div style="text-align:center">
<strong>Size</strong>
</div></th>
<th><div style="text-align:center">
<strong>Partial</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp"><em>generic</em></code></td>
<td><code class="sourceCode cpp">n</code></td>
<td><code class="sourceCode cpp">k</code></td>
<td><code class="sourceCode cpp">b</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">chunk</code></td>
<td><code class="sourceCode cpp">k</code></td>
<td><code class="sourceCode cpp">k</code></td>
<td><code class="sourceCode cpp"><span class="kw">true</span></code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">slide</code></td>
<td><code class="sourceCode cpp"><span class="dv">1</span></code></td>
<td><code class="sourceCode cpp">k</code></td>
<td><code class="sourceCode cpp"><span class="kw">false</span></code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">stride</code></td>
<td><code class="sourceCode cpp">k</code></td>
<td><code class="sourceCode cpp"><span class="dv">1</span></code></td>
<td>N/A</td>
</tr>
</tbody>
</table>
<p>The above table isn’t <em>quite</em> right - since <code class="sourceCode cpp">stride</code> does not give you a range of ranges, so it would unfortunately not be implementable in terms of <code class="sourceCode cpp"><em>generic</em></code>. And as with <code class="sourceCode cpp">tail</code> vs <code class="sourceCode cpp">drop</code>, we have the question here of should <code class="sourceCode cpp">chunk</code> and <code class="sourceCode cpp">slide</code> each be first-class views or should they both be implemented in terms of <code class="sourceCode cpp"><em>generic</em></code>? Implementing in terms of <code class="sourceCode cpp"><em>generic</em></code> saves specification effort and gives us a more generic algorithm, but means we would have to store two extra data members than would be necessary in first-class implementation.</p>
<p>Moreover, as a language without named arguments, we have a different problem when it comes to <code class="sourceCode cpp"><em>generic</em></code> here. It takes two <code class="sourceCode cpp"><span class="dt">int</span></code>s and a <code class="sourceCode cpp"><span class="dt">bool</span></code>. There is no natural order for these parameters, so who knows what <code class="sourceCode cpp"><em>generic</em><span class="op">(</span><span class="dv">1</span>, <span class="dv">4</span>, <span class="kw">false</span><span class="op">)</span></code> means — especially since <code class="sourceCode cpp"><em>generic</em><span class="op">(</span><span class="kw">false</span>, <span class="dv">1</span>, <span class="dv">4</span><span class="op">)</span></code> would also compile. This suggests simply not having it as a user-facing algorithm. Or we could use an aggregate to mock up named arguments via designated-initializers, as in <code class="sourceCode cpp"><em>generic</em><span class="op">({.</span>step<span class="op">=</span><span class="dv">1</span>, <span class="op">.</span>size<span class="op">=</span><span class="dv">4</span>, <span class="op">.</span>partial<span class="op">=</span><span class="kw">false</span><span class="op">})</span></code>. This is a very useful pattern, but one which has no precedent in the standard library as of this writing.</p>
<p>Ultimately, we don’t think an algorithm like <code class="sourceCode cpp"><em>generic</em></code> would necessarily be useful for C++, and it wouldn’t really help much in specifying either <code class="sourceCode cpp">chunk</code> or <code class="sourceCode cpp">slide</code> (and definitely not <code class="sourceCode cpp">stride</code>). But these are important algorithms that come up frequently enough to be in consideration for Tier 1.</p>
<h2 data-number="4.6" id="the-takedrop-family"><span class="header-section-number">4.6</span> The take/drop family<a href="#the-takedrop-family" class="self-link"></a></h2>
<p>In C++20 already we have several views that pass through some subset of the initial range — without modifying any of the elements. Those are: <code class="sourceCode cpp">take</code>, <code class="sourceCode cpp">take_while</code>, <code class="sourceCode cpp">drop</code>, and <code class="sourceCode cpp">drop_while</code>. There are actually many more algorithms in this family that are all quite similar. Nearly all of these range adapters can be implemented in terms of adapters that already exist, although we can typically do better if we make them all first-class. The question is really what is it that we want to do here?</p>
<p>We already discussed the example of <code class="sourceCode cpp">tail</code> earlier — should this be a first-class view or is <code class="sourceCode cpp">drop<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code> sufficient? The same question applies to most of the views in this list, and we generally have the same answer for all of them: if we’re okay with derivative implementations, then we might as well make all of them Tier 1 since they would all have single-sentence specifications; but if we want better implementations, then they’re certainly not important enough to gain get top priority, so we would move them down to Tier 2 or Tier 3.</p>
<p>The potential adoption of <code class="sourceCode cpp"><span class="op">|&gt;</span></code> as a language feature <span class="citation" data-cites="P2011R1">[<a href="#ref-P2011R1" role="doc-biblioref">P2011R1</a>]</span> also affects the calculus here, as most of these could also be implemented as simple functions and relying on <code class="sourceCode cpp"><span class="op">|&gt;</span></code> instead of <code class="sourceCode cpp"><span class="op">|</span></code> to do the piping. For example, <code class="sourceCode cpp">tail</code> could be implemented (<span class="citation" data-cites="P1739R4">[<a href="#ref-P1739R4" role="doc-biblioref">P1739R4</a>]</span> notwithstanding):</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a><span class="kw">template</span> <span class="op">&lt;</span>viewable_range R<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2"></a><span class="kw">auto</span> tail<span class="op">(</span>R<span class="op">&amp;&amp;</span> range<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3"></a>    <span class="kw">auto</span> b <span class="op">=</span> ranges<span class="op">::</span>begin<span class="op">(</span>range<span class="op">)</span>;</span>
<span id="cb23-4"><a href="#cb23-4"></a>    <span class="kw">auto</span> e <span class="op">=</span> ranges<span class="op">::</span>end<span class="op">(</span>range<span class="op">)</span>;</span>
<span id="cb23-5"><a href="#cb23-5"></a>    <span class="cf">if</span> <span class="op">(</span>b <span class="op">!=</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-6"><a href="#cb23-6"></a>        <span class="op">++</span>b;</span>
<span id="cb23-7"><a href="#cb23-7"></a>    <span class="op">}</span></span>
<span id="cb23-8"><a href="#cb23-8"></a>    <span class="cf">return</span> subrange<span class="op">(</span>b, e<span class="op">)</span>;</span>
<span id="cb23-9"><a href="#cb23-9"></a><span class="op">}</span></span></code></pre></div>
<p>We’ll go through the other potential range adapters in this family and discuss how they could be implemented in terms of existing adapters:</p>
<ul>
<li><code class="sourceCode cpp">take_last<span class="op">(</span>N<span class="op">)</span></code> and <code class="sourceCode cpp">drop_last<span class="op">(</span>N<span class="op">)</span></code>. <code class="sourceCode cpp">views<span class="op">::</span>take_last<span class="op">(</span>N<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">views<span class="op">::</span>reverse <span class="op">|</span> views<span class="op">::</span>take<span class="op">(</span>N<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>reverse</code>. But this is somewhat expensive, especially for non-common views. For random-access, sized ranges, we’re probably want <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>take_last<span class="op">(</span>N<span class="op">)</span></code> to evaluate as <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>drop<span class="op">(</span>r<span class="op">.</span>size<span class="op">()</span> <span class="op">-</span> N<span class="op">)</span></code>, and that desire is really the crux of this whole question — is the equivalent version good enough or should we want to do it right?</li>
<li><code class="sourceCode cpp">take_last_while<span class="op">(</span>P<span class="op">)</span></code> and <code class="sourceCode cpp">drop_last_while<span class="op">(</span>P<span class="op">)</span></code>. These likewise could be implemented in terms of double-reverse, but <code class="sourceCode cpp">take_last_while</code> could not be implemented in terms of <code class="sourceCode cpp">drop_while</code>.</li>
<li><code class="sourceCode cpp">take_exactly<span class="op">(</span>N<span class="op">)</span></code> and <code class="sourceCode cpp">drop_exactly<span class="op">(</span>N<span class="op">)</span></code>. These are similar to <code class="sourceCode cpp">take</code> and <code class="sourceCode cpp">drop</code> except not checked. <code class="sourceCode cpp">iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">3</span><span class="op">)</span> <span class="op">|</span> take<span class="op">(</span><span class="dv">5</span><span class="op">)</span></code> is a valid empty range, while <code class="sourceCode cpp">iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">3</span><span class="op">)</span> <span class="op">|</span> take_exactly<span class="op">(</span><span class="dv">5</span><span class="op">)</span></code> is undefined behavior.</li>
<li><code class="sourceCode cpp">slice<span class="op">(</span>M, N<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">views<span class="op">::</span>drop<span class="op">(</span>M<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>take<span class="op">(</span>N <span class="op">-</span> M<span class="op">)</span></code>, and you couldn’t do much better as a first class view. range-v3 also supports a flavor that works as <code class="sourceCode cpp">views<span class="op">::</span>slice<span class="op">(</span>M, end <span class="op">-</span> N<span class="op">)</span></code> for a special variable <code class="sourceCode cpp">end</code>, which likewise be equivalent to <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>drop<span class="op">(</span>M<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>drop_last<span class="op">(</span>N<span class="op">)</span></code>.</li>
<li><code class="sourceCode cpp">head</code> is equivalent to <code class="sourceCode cpp">views<span class="op">::</span>drop_last<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code>.</li>
<li><code class="sourceCode cpp">tail</code> is equivalent to <code class="sourceCode cpp">views<span class="op">::</span>drop<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code>.</li>
<li><code class="sourceCode cpp">trim<span class="op">(</span>P<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">views<span class="op">::</span>drop_while<span class="op">(</span>P<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>drop_last_while<span class="op">(</span>P<span class="op">)</span></code>.</li>
<li><code class="sourceCode cpp">delimit<span class="op">(</span>V<span class="op">)</span></code> has two flavors. When called with a range, <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>delimit<span class="op">(</span>V<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>take_while<span class="op">([</span>V<span class="op">](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> e<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">!(</span>e <span class="op">==</span> V<span class="op">)</span>; <span class="op">})</span></code>. But it also allows wrapping an iterator, such that <code class="sourceCode cpp">views<span class="op">::</span>delimit<span class="op">(</span>it, V<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">subrange<span class="op">(</span>it, unreachable_sentinel<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>delimit<span class="op">(</span>V<span class="op">)</span></code>.</li>
</ul>
<p>We’re tentatively labelling the more complicated ones here Tier 2 and the more trivial (i.e. <code class="sourceCode cpp">head</code>, <code class="sourceCode cpp">tail</code>, and <code class="sourceCode cpp">slice</code>) and possibly less needed (i.e. <code class="sourceCode cpp">meow_exactly</code>) ones Tier 3.</p>
<h2 data-number="4.7" id="generative-factories"><span class="header-section-number">4.7</span> Generative factories<a href="#generative-factories" class="self-link"></a></h2>
<p>There are several views on the list that are simply factories — they cannot be piped into. So we’ll consider them as their own family:</p>
<ul>
<li><code class="sourceCode cpp">cartesian_product<span class="op">(</span>E<span class="op">...)</span></code> takes a bunch of ranges and yields a range of tuples that are the Cartesian product of those ranges.</li>
<li><code class="sourceCode cpp">concat<span class="op">(</span>E<span class="op">...)</span></code> concatenates a bunch of ranges together, it must be a standalone range. It is also sometimes called <code class="sourceCode cpp">chain</code>.</li>
<li><code class="sourceCode cpp">generate<span class="op">(</span>F<span class="op">)</span></code> takes a nullary function <code class="sourceCode cpp">F</code> and produces an infinite range of invoking that function.</li>
<li><code class="sourceCode cpp">generate_n<span class="op">(</span>F, N<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">generate<span class="op">(</span>F<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>take<span class="op">(</span>N<span class="op">)</span></code>.</li>
<li><code class="sourceCode cpp">linear_distribute<span class="op">(</span>B, E, N<span class="op">)</span></code> produces a range of <code class="sourceCode cpp">N</code> values linearly distributed from <code class="sourceCode cpp">B</code> to <code class="sourceCode cpp">E</code>.</li>
<li><code class="sourceCode cpp">repeat<span class="op">(</span>V<span class="op">)</span></code> is an infinite range of a single value, equivalent to <code class="sourceCode cpp">generate<span class="op">([</span>V<span class="op">]{</span> <span class="cf">return</span> V; <span class="op">})</span></code>.</li>
<li><code class="sourceCode cpp">repeat_n<span class="op">(</span>V, N<span class="op">)</span></code> is <code class="sourceCode cpp">N</code> copies of <code class="sourceCode cpp">V</code>, equivalent to <code class="sourceCode cpp">generate_n<span class="op">([</span>V<span class="op">]{</span> <span class="cf">return</span> V; <span class="op">}</span>, N<span class="op">)</span></code>.</li>
</ul>
<p>These vary wildly in complexity (<code class="sourceCode cpp">repeat</code> is certainly far simpler than <code class="sourceCode cpp">cartesian_product</code>). But <code class="sourceCode cpp">cartesian_product</code> comes up sufficiently often and are sufficiently complicated to merit Tier 1 priority.</p>
<p>The rest, we consider lower priority. And <code class="sourceCode cpp">generate</code> and <code class="sourceCode cpp">generate_n</code> in particular need special care to deal with <span>16.4.6.10 <a href="https://wg21.link/res.on.data.races">[res.on.data.races]</a></span>. The current implementation of <code class="sourceCode cpp">generate_n</code> in range-v3 has a data race.</p>
<h2 data-number="4.8" id="other-view-adapters"><span class="header-section-number">4.8</span> Other view adapters<a href="#other-view-adapters" class="self-link"></a></h2>
<p>Other range adapters that we haven’t talked about yet, but aren’t sure how to group exactly, are:</p>
<ul>
<li><code class="sourceCode cpp">adjacent_filter<span class="op">(</span>P<span class="op">)</span></code> is an extension of <code class="sourceCode cpp">filter</code> that rather than taking a unary predicate and going one element at a take takes a binary predicate and goes pairwise through the elements. Similar to <code class="sourceCode cpp">adjacent <span class="op">|</span> filter<span class="op">(</span><em>applied</em><span class="op">(</span>P<span class="op">))</span> <span class="op">|</span> views<span class="op">::</span>keys</code> except that it always keeps the first element.</li>
<li><code class="sourceCode cpp">adjacent_remove_if<span class="op">(</span>P<span class="op">)</span></code> is similar to <code class="sourceCode cpp">adjacent_filter<span class="op">(</span>not_fn<span class="op">(</span>P<span class="op">))</span></code>, except that it always keeps the last element.</li>
<li><code class="sourceCode cpp">cycle<span class="op">(</span>R<span class="op">)</span></code> produces an infinite ranges that, well, cycles through <code class="sourceCode cpp">R</code> repeatedly.</li>
<li><code class="sourceCode cpp">scan<span class="op">(</span>R, F, V<span class="op">)</span></code> is the lazy view version of <code class="sourceCode cpp">std<span class="op">::</span>inclusive_scan</code>, except not having a defaulted binary operation.</li>
<li><code class="sourceCode cpp">intersperse<span class="op">(</span>V<span class="op">)</span></code> produces a new range alternating selecting elements from the source range and the value <code class="sourceCode cpp">V</code></li>
<li><code class="sourceCode cpp">join_with<span class="op">(</span>V<span class="op">)</span></code>. C++20 has a version of <code class="sourceCode cpp">join</code> that does not take a delimiter, but we really do need a version that provides one as well. The issue with taking a delimiter is that there is an ambiguity with what <code class="sourceCode cpp">r <span class="op">|</span> views<span class="op">::</span>join<span class="op">(</span>v<span class="op">)</span></code> means, if <code class="sourceCode cpp">v</code> happens to itself be a joinable range. range-v3 assumes that if <code class="sourceCode cpp">v</code> is a joinable range that <code class="sourceCode cpp">views<span class="op">::</span>join<span class="op">(</span>v<span class="op">)</span></code> joins it without a delimiter. We think this ship has sailed in C++20, and it would be better to introduce <code class="sourceCode cpp">join_with</code> that requires a delimiter. See <span class="citation" data-cites="P2441R0">[<a href="#ref-P2441R0" role="doc-biblioref">P2441R0</a>]</span>.</li>
<li><code class="sourceCode cpp">partial_sum<span class="op">(</span>R<span class="op">)</span></code> is equivalent to <code class="sourceCode cpp">scan<span class="op">(</span>R, std<span class="op">::</span>plus<span class="op">&lt;&gt;())</span></code>.</li>
<li><code class="sourceCode cpp">split_when<span class="op">(</span>P<span class="op">)</span></code> is a more complicated version of <code class="sourceCode cpp">split</code> that rather than taking a value or a range, instead takes a predicate that could also return an iterator.</li>
<li><code class="sourceCode cpp">sample<span class="op">(</span>N<span class="op">)</span></code> yields a random sample of the given length.</li>
</ul>
<p>There are other combinatoric generators that also could be explored. For example, Python has <code class="sourceCode cpp">itertools<span class="op">.</span>product</code>, <code class="sourceCode cpp">itertools<span class="op">.</span>combinations</code>, and <code class="sourceCode cpp">itertools<span class="op">.</span>combination_with_replacement</code> which all operate on a single range of <code class="sourceCode cpp">T</code> and produce a range of range of <code class="sourceCode cpp">T</code>.</p>
<p>Of these, <code class="sourceCode cpp">views<span class="op">::</span>join_with</code> fills in an incomplete aspect of the already-existing <code class="sourceCode cpp">views<span class="op">::</span>join</code>, so we feel that it is a Tier 1 view. The rest we consider to have lower priority.</p>
<h2 data-number="4.9" id="derivatives-of-transform"><span class="header-section-number">4.9</span> Derivatives of <code class="sourceCode cpp">transform</code><a href="#derivatives-of-transform" class="self-link"></a></h2>
<p>Several of the above views that are labeled “not proposed” are variations on a common theme: <code class="sourceCode cpp">addressof</code>, <code class="sourceCode cpp">indirect</code>, and <code class="sourceCode cpp">move</code> are all basically wrappers around <code class="sourceCode cpp">transform</code> that take <code class="sourceCode cpp">std<span class="op">::</span>addressof</code>, <code class="sourceCode cpp">std<span class="op">::</span>dereference</code> (a function object we do not have at the moment), and <code class="sourceCode cpp">std<span class="op">::</span>move</code>, respectively. Basically, but not exactly, since one of those functions doesn’t exist yet and the other three we can’t pass as an argument anyway.</p>
<p>But some sort of broader ability to pass functions into functions would mostly alleviate the need for these. <code class="sourceCode cpp">views<span class="op">::</span>addressof</code> is shorter than <code class="sourceCode cpp">views<span class="op">::</span>transform<span class="op">(</span>LIFT<span class="op">(</span>std<span class="op">::</span>addressof<span class="op">))</span></code> (assuming a <code class="sourceCode cpp">LIFT</code> macro that wraps a name and emits a lambda), but we’re not sure that we necessarily need to add special cases of <code class="sourceCode cpp">transform</code> for every useful function.</p>
<h3 data-number="4.9.1" id="viewsas_const"><span class="header-section-number">4.9.1</span> <code class="sourceCode cpp">views<span class="op">::</span>as_const</code><a href="#viewsas_const" class="self-link"></a></h3>
<p>There’s one that stands out as being slightly different though: <code class="sourceCode cpp">views<span class="op">::</span>as_const</code> isn’t quite the same as a <code class="sourceCode cpp">transform</code> over <code class="sourceCode cpp">std<span class="op">::</span>as_const</code>, because of the existence of proxy references. <code class="sourceCode cpp">std<span class="op">::</span>as_const</code> only accepts lvalues, so something like:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></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="cb24-2"><a href="#cb24-2"></a>views<span class="op">::</span>zip<span class="op">(</span>v<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>LIFT<span class="op">(</span>std<span class="op">::</span>as_const<span class="op">))</span>;</span></code></pre></div>
<p>would not compile. And were it to compile, what should it actually mean? <code class="sourceCode cpp">zip</code>’s <code class="sourceCode cpp">reference</code> type here, as previously discussed, should be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span></code>. What would a <code class="sourceCode cpp"><span class="kw">const</span></code> view over this range mean? Should we transparently propagate prvalues, thereby being a shallow <code class="sourceCode cpp"><span class="kw">const</span></code>, and produce a new range whose <code class="sourceCode cpp">reference</code> is <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span></code>? Or should we somehow come up with a way to do deep <code class="sourceCode cpp"><span class="kw">const</span></code>-ness here and yield a range whose <code class="sourceCode cpp">reference</code> is <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="kw">const</span><span class="op">&amp;&gt;</span></code>? The latter noting that we are not doing this sort of introspection for <code class="sourceCode cpp">views<span class="op">::</span>zip_transform</code>.</p>
<p>In range-v3, the <code class="sourceCode cpp">reference</code> type is <code class="sourceCode cpp">common_reference_t<span class="op">&lt;</span>range_value_t<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;&amp;</span>, range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></code>. In this particular example, that would be <code class="sourceCode cpp">std<span class="op">::</span>tuple<span class="op">&lt;</span><span class="dt">int</span> <span class="kw">const</span><span class="op">&amp;&gt;</span></code> (following the various <code class="sourceCode cpp">tuple</code> changes performed to implement <code class="sourceCode cpp">zip</code> in <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>), which is exactly what you want.</p>
<p>Having a <code class="sourceCode cpp"><span class="kw">const</span></code> view over a range is something that seems inherently useful and is more complex than simply a <code class="sourceCode cpp">transform</code> over <code class="sourceCode cpp">std<span class="op">::</span>as_const</code>, and has proven to be in high demand. The full design is explored in <span class="citation" data-cites="P2278R1">[<a href="#ref-P2278R1" role="doc-biblioref">P2278R1</a>]</span> and is Tier 1 material.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="algorithms"><span class="header-section-number">5</span> Algorithms<a href="#algorithms" class="self-link"></a></h1>
<p>The largest chunk of C++20 Ranges were the algorithms, and the work here has been very thorough. All the <code class="sourceCode cpp"><span class="op">&lt;</span>algorithm<span class="op">&gt;</span></code>s have been range-ified, which has been fantastic.</p>
<p>But there are a few algorithms that aren’t in <code class="sourceCode cpp"><span class="op">&lt;</span>algorithm<span class="op">&gt;</span></code> that do not have range-based versions: those that are in <code class="sourceCode cpp"><span class="op">&lt;</span>numeric<span class="op">&gt;</span></code>. These are often the last algorithms considered for anything, they were the last algorithms that were made <code class="sourceCode cpp"><span class="kw">constexpr</span></code> (<span class="citation" data-cites="P1645R1">[<a href="#ref-P1645R1" role="doc-biblioref">P1645R1</a>]</span>) and now are the last to become range-based. They are:</p>
<table>
<colgroup>
<col style="width: 52%"></col>
<col style="width: 47%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Algorithm</strong>
</div></th>
<th><div style="text-align:center">
<strong>Priority</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">iota</code></td>
<td><span class="addu">Tier 1</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">shift_left</code></td>
<td><span class="addu">Tier 1</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">shift_right</code></td>
<td><span class="addu">Tier 1</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">accumulate</code></td>
<td><span class="addu">Tier 1, renamed to <code class="sourceCode cpp">fold</code>.</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">reduce</code></td>
<td><span class="yellow">Tier 2, along with <code class="sourceCode cpp">sum</code> and <code class="sourceCode cpp">product</code>.</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">transform_reduce</code></td>
<td>Not proposed.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">inner_product</code></td>
<td>Not proposed.</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">adjacent_difference</code></td>
<td><span class="diffdel">Tier 3, renamed to <code class="sourceCode cpp">adjacent_transform</code></span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">partial_sum</code></td>
<td><span class="diffdel">Tier 3, but without a binary operation parameter. Also adding <code class="sourceCode cpp">partial_fold</code>.</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">inclusive_scan</code></td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">exclusive_scan</code></td>
<td><span class="diffdel">Tier 3</span></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">transform_inclusive_scan</code></td>
<td>Not proposed.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">transform_exclusive_scan</code></td>
<td>Not proposed.</td>
</tr>
</tbody>
</table>
<p>What to do about these algorithms? Well, one of the big motivations for Ranges was the ability to actually compose algorithms. This severely reduces the need for the combinatorial explosion of algorithms - all the <code class="sourceCode cpp">transform_meow</code> algorithms are <code class="sourceCode cpp">transform</code> followed by <code class="sourceCode cpp">meow</code>, so we probably don’t need separate range-based algorithms for those.</p>
<p>Four of these (<code class="sourceCode cpp">accumulate</code>, <code class="sourceCode cpp">reduce</code>, <code class="sourceCode cpp">transform_reduce</code>, and <code class="sourceCode cpp">inner_product</code>) return a value, while the other seven output a range (one through a pair of writable iterators and the other six through an output iterator). We’ll consider these separately.</p>
<h2 data-number="5.1" id="algorithms-that-output-a-value-catamorphisms"><span class="header-section-number">5.1</span> Algorithms that Output a Value (Catamorphisms)<a href="#algorithms-that-output-a-value-catamorphisms" class="self-link"></a></h2>
<h3 data-number="5.1.1" id="stdaccumulate-rangesfold"><span class="header-section-number">5.1.1</span> <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code><a href="#stdaccumulate-rangesfold" class="self-link"></a></h3>
<p>We think having a range-based left-fold algorithm in the standard library is very important, since this is such a fundamental algorithm. Indeed, several of the other standard library algorithms <em>are</em> simple folds — for instance <code class="sourceCode cpp">count</code>, <code class="sourceCode cpp">count_if</code>, <code class="sourceCode cpp">max_element</code>, <code class="sourceCode cpp">min_element</code>, <code class="sourceCode cpp">minmax_element</code>, and <code class="sourceCode cpp">inner_product</code>. We don’t have a generic range-based <code class="sourceCode cpp">max</code> or <code class="sourceCode cpp">min</code> (just ones that takes an <code class="sourceCode cpp">initializer_list</code>), but those would also be a left-folds. As such , we think adding such a left-fold to the standard library is a top tier priority for C++23. Except that we think this algorithm should be named <span class="addu"><code class="sourceCode cpp">ranges<span class="op">::</span>fold</code></span> - the problem with the name <code class="sourceCode cpp">accumulate</code> is that it is strongly suggestive of addition, which makes uses of it over different operations just very strange. <code class="sourceCode cpp">fold</code> is what the algorithm is, and has no such emphasis. It’s the more generic name, for the most generic algorithm.</p>
<p><span class="citation" data-cites="P1813R0">[<a href="#ref-P1813R0" role="doc-biblioref">P1813R0</a>]</span> goes through the work of introducing a set of constraints for these algorithms, and its suggestion for this algorithm is:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a><span class="kw">template</span> <span class="op">&lt;</span>input_range R, movable T, <span class="kw">class</span> Proj <span class="op">=</span> identity,</span>
<span id="cb25-2"><a href="#cb25-2"></a>          indirect_magma<span class="op">&lt;</span><span class="kw">const</span> T<span class="op">*</span>, projected<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, Proj<span class="op">&gt;</span>, T<span class="op">*&gt;</span> BOp <span class="op">=</span> ranges<span class="op">::</span>plus<span class="op">&gt;</span></span>
<span id="cb25-3"><a href="#cb25-3"></a><span class="kw">constexpr</span> accumulate_result<span class="op">&lt;</span>safe_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, T<span class="op">&gt;</span></span>
<span id="cb25-4"><a href="#cb25-4"></a>    accumulate<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, T init, BOp bop <span class="op">=</span> <span class="op">{}</span>, Proj proj <span class="op">=</span> <span class="op">{})</span>;</span></code></pre></div>
<p>We think this is a bad direction, for three reasons.</p>
<p>First, we should not default the binary operation at all. Having a default <code class="sourceCode cpp">fold</code> operation doesn’t make much sense - it’s reasonable for <code class="sourceCode cpp">ranges<span class="op">::</span>sort</code> to default to sorting by <code class="sourceCode cpp"><span class="op">&lt;</span></code>, since the entire standard library is built on <code class="sourceCode cpp"><span class="op">&lt;</span></code> as the primary comparison operator, but that doesn’t really hold for <code class="sourceCode cpp"><span class="op">+</span></code>. Instead, we should add separate named algorithms <span class="addu"><code class="sourceCode cpp">ranges<span class="op">::</span>sum</code></span> and <span class="addu"><code class="sourceCode cpp">ranges<span class="op">::</span>product</code></span> that just invoke <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> with <code class="sourceCode cpp">std<span class="op">::</span>plus<span class="op">()</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>multiplies<span class="op">()</span></code> – or more likely that these invoke <code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code> instead as the more efficient algorithm with more constraints.</p>
<p>Second, the above definition definitely follows Alexander Stepanov’s law of useful return <span class="citation" data-cites="stepanov">[<a href="#ref-stepanov" role="doc-biblioref">stepanov</a>]</span> (emphasis ours):</p>
<div class="quote">
<p>When writing code, it’s often the case that you end up computing a value that the calling function doesn’t currently need. Later, however, this value may be important when the code is called in a different situation. In this situation, you should obey the law of useful return: <em>A procedure should return all the potentially useful information it computed.</em></p>
</div>
<p>But it makes the usage of the algorithm quite cumbersome. The point of a fold is to return the single value. We would just want to write:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1"></a><span class="dt">int</span> total <span class="op">=</span> ranges<span class="op">::</span>sum<span class="op">(</span>numbers<span class="op">)</span>;</span></code></pre></div>
<p>Rather than:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a><span class="kw">auto</span> <span class="op">[</span>_, total<span class="op">]</span> <span class="op">=</span> ranges<span class="op">::</span>sum<span class="op">(</span>numbers<span class="op">)</span>;</span></code></pre></div>
<p>or:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1"></a><span class="dt">int</span> total <span class="op">=</span> ranges<span class="op">::</span>sum<span class="op">(</span>numbers, <span class="dv">0</span><span class="op">).</span>value;</span></code></pre></div>
<p><code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> should just return <code class="sourceCode cpp">T</code>. This would be consistent with what the other range-based folds already return in C++20 (e.g. <code class="sourceCode cpp">ranges<span class="op">::</span>count</code> returns a <code class="sourceCode cpp">range_difference_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>any_of</code> - which can’t quite be a <code class="sourceCode cpp">fold</code> due to wanting to short-circuit - just returns <code class="sourceCode cpp"><span class="dt">bool</span></code>).</p>
<p>Third, these constraints are far too restrictive. Copying the proposed definition of <code class="sourceCode cpp">magma</code> and <code class="sourceCode cpp">indirect_magma</code> here for readability:</p>
<div class="quote">
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1"></a><span class="co">// section 3.2.2 from P1813R0</span></span>
<span id="cb29-2"><a href="#cb29-2"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> BOp, <span class="kw">class</span> T, <span class="kw">class</span> U<span class="op">&gt;</span></span>
<span id="cb29-3"><a href="#cb29-3"></a><span class="kw">concept</span> magma <span class="op">=</span></span>
<span id="cb29-4"><a href="#cb29-4"></a>    common_with<span class="op">&lt;</span>T, U<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-5"><a href="#cb29-5"></a>    regular_invocable<span class="op">&lt;</span>BOp, T, T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-6"><a href="#cb29-6"></a>    regular_invocable<span class="op">&lt;</span>BOp, U, U<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-7"><a href="#cb29-7"></a>    regular_invocable<span class="op">&lt;</span>BOp, T, U<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-8"><a href="#cb29-8"></a>    regular_invocable<span class="op">&lt;</span>BOp, U, T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-9"><a href="#cb29-9"></a>    common_with<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, T, U<span class="op">&gt;</span>, T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-10"><a href="#cb29-10"></a>    common_with<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, T, U<span class="op">&gt;</span>, U<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb29-11"><a href="#cb29-11"></a>    same_as<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, T, U<span class="op">&gt;</span>, invoke_result_t<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, U, T<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>Let <code class="sourceCode cpp">bop</code> be an object of type <code class="sourceCode cpp">BOp</code>, <code class="sourceCode cpp">t</code> be an object of type <code class="sourceCode cpp">T</code>, and <code class="sourceCode cpp">u</code> be an object of type <code class="sourceCode cpp">U</code>. The value <code class="sourceCode cpp">invoke<span class="op">(</span>bop, t, u<span class="op">)</span></code> must return a result that is representable by <code class="sourceCode cpp">common_type_t<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code>.</p>
<p>The decision to require common types for a over <code class="sourceCode cpp">magma<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> is similar to the reason that <code class="sourceCode cpp">equality_comparable_with</code> requires <code class="sourceCode cpp">common_reference_with</code>: this ensures that when an algorithm requires a <code class="sourceCode cpp">magma</code>,we are able to <em>equationally reason</em> about those requirements. It’s possible to overload <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">+(</span><span class="dt">int</span>,vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;)</span></code>, but that doesn’t follow the canonical usage of <code class="sourceCode cpp"><span class="op">+</span></code>. Does <code class="sourceCode cpp"><span class="dv">1</span> <span class="op">+</span> vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code> mean “concatenate <code class="sourceCode cpp">vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code> to the end of a temporary <code class="sourceCode cpp">vector<span class="op">{</span><span class="dv">1</span><span class="op">}</span></code>”? Is it a shorthand for <code class="sourceCode cpp">accumulate<span class="op">(</span>vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, <span class="dv">1</span><span class="op">)</span></code>? The intention is unclear, and so <code class="sourceCode cpp">std<span class="op">::</span>plus<span class="op">&lt;&gt;</span></code> should not model <code class="sourceCode cpp">magma<span class="op">&lt;</span><span class="dt">int</span>, vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;</span></code>.</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1"></a><span class="co">// section 3.2.11 from P1813R0</span></span>
<span id="cb30-2"><a href="#cb30-2"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> BOp, <span class="kw">class</span> I1, <span class="kw">class</span> I2, <span class="kw">class</span> O<span class="op">&gt;</span></span>
<span id="cb30-3"><a href="#cb30-3"></a><span class="kw">concept</span> indirect_magma <span class="op">=</span></span>
<span id="cb30-4"><a href="#cb30-4"></a>    readable<span class="op">&lt;</span>I1<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-5"><a href="#cb30-5"></a>    readable<span class="op">&lt;</span>I2<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-6"><a href="#cb30-6"></a>    writable<span class="op">&lt;</span>O, indirect_result_t<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, I1, I2<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-7"><a href="#cb30-7"></a>    magma<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, iter_value_t<span class="op">&lt;</span>I1<span class="op">&gt;&amp;</span>, iter_value_t<span class="op">&lt;</span>I2<span class="op">&gt;&amp;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-8"><a href="#cb30-8"></a>    magma<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, iter_value_t<span class="op">&lt;</span>I1<span class="op">&gt;&amp;</span>, iter_reference_t<span class="op">&lt;</span>I2<span class="op">&gt;&amp;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-9"><a href="#cb30-9"></a>    magma<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, iter_reference_t<span class="op">&lt;</span>I1<span class="op">&gt;</span>, iter_value_t<span class="op">&lt;</span>I2<span class="op">&gt;&amp;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-10"><a href="#cb30-10"></a>    magma<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, iter_reference_t<span class="op">&lt;</span>I1<span class="op">&gt;</span>, iter_reference_t<span class="op">&lt;</span>I2<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb30-11"><a href="#cb30-11"></a>    magma<span class="op">&lt;</span>BOp<span class="op">&amp;</span>, iter_common_reference_t<span class="op">&lt;</span>I1<span class="op">&gt;</span>, iter_common_reference_t<span class="op">&lt;</span>I2<span class="op">&gt;&gt;</span>;</span></code></pre></div>
</div>
<p>We see here again the heavy association of <code class="sourceCode cpp">plus</code> with <code class="sourceCode cpp">accumulate</code>, hence again the desire to rename the algorithm to <code class="sourceCode cpp">fold</code>. But the important thing to consider here is the requirement that the binary function <em>need</em> be invokable on each type and that there <em>need</em> be a common type for the result. We’ve already been through this process with the ranges comparison algorithms in <span class="citation" data-cites="P1716R3">[<a href="#ref-P1716R3" role="doc-biblioref">P1716R3</a>]</span> and removed those restrictions.</p>
<p>Consider a simple fold counting the occurences of a string (i.e. how you would implement <code class="sourceCode cpp">ranges<span class="op">::</span>count</code> with <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code>):</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> words <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb31-2"><a href="#cb31-2"></a><span class="dt">int</span> n <span class="op">=</span> ranges<span class="op">::</span>fold<span class="op">(</span>words, <span class="dv">0</span>, <span class="op">[](</span><span class="dt">int</span> accum, std<span class="op">::</span>string <span class="kw">const</span><span class="op">&amp;</span> w<span class="op">){</span></span>
<span id="cb31-3"><a href="#cb31-3"></a>    <span class="cf">return</span> accum <span class="op">+</span> <span class="op">(</span>w <span class="op">==</span> <span class="st">&quot;range&quot;</span><span class="op">)</span>;</span>
<span id="cb31-4"><a href="#cb31-4"></a><span class="op">})</span>;</span></code></pre></div>
<p>Such an algorithm would not meet the requirements laid out in P1813. There’s no common type between <code class="sourceCode cpp"><span class="dt">int</span></code> and <code class="sourceCode cpp">string</code>, that lambda is only invocable with one of the possible four orders of arguments. But it’s a perfectly reasonable fold. Instead, the only allowed implementation would be:</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1"></a><span class="dt">int</span> n <span class="op">=</span> ranges<span class="op">::</span>fold<span class="op">(</span>words, <span class="dv">0</span>, ranges<span class="op">::</span>plus<span class="op">{}</span>, <span class="op">[](</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&amp;</span> w<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> w <span class="op">==</span> <span class="st">&quot;ranges&quot;</span>; <span class="op">})</span>;</span></code></pre></div>
<p>But we’re hard-pressed to explain why this would be considered better. In the general case, there may not even be an allowed implementation. Consider wanting to score a word in Scrabble. In Scrabble, each letter has a value but each tile can either multiply the score of a single letter or multiple the score of the whole word. One way to compute the score then is to use two <code class="sourceCode cpp">fold</code>s, one to figure out the world multiplier and another to figure out the letter sum:</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1"></a><span class="kw">struct</span> Square <span class="op">{</span> <span class="dt">int</span> letter_multiplier, word_multiplier; <span class="op">}</span>;</span>
<span id="cb33-2"><a href="#cb33-2"></a>vector<span class="op">&lt;</span>Square<span class="op">&gt;</span> squares <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb33-3"><a href="#cb33-3"></a>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> letters <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb33-4"><a href="#cb33-4"></a></span>
<span id="cb33-5"><a href="#cb33-5"></a><span class="dt">int</span> score <span class="op">=</span> fold<span class="op">(</span>squares, <span class="dv">1</span>, multiplies<span class="op">()</span>, <span class="op">&amp;</span>Square<span class="op">::</span>word_multiplier<span class="op">)</span></span>
<span id="cb33-6"><a href="#cb33-6"></a>          <span class="op">*</span> fold<span class="op">(</span>zip_transform<span class="op">(</span>multiplies<span class="op">()</span>,</span>
<span id="cb33-7"><a href="#cb33-7"></a>                          squares <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(&amp;</span>Square<span class="op">::</span>letter_multiplier<span class="op">)</span>,</span>
<span id="cb33-8"><a href="#cb33-8"></a>                          letters<span class="op">)</span>,</span>
<span id="cb33-9"><a href="#cb33-9"></a>                 <span class="dv">0</span>, plus<span class="op">())</span>;</span></code></pre></div>
<p>Another way is to keep a running sum of the two parts separately, and do a manual multiply:</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1"></a><span class="kw">struct</span> Accum <span class="op">{</span></span>
<span id="cb34-2"><a href="#cb34-2"></a>    <span class="dt">int</span> result<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> total <span class="op">*</span> multiplier; <span class="op">}</span>;</span>
<span id="cb34-3"><a href="#cb34-3"></a>    <span class="dt">int</span> multiplier, total;</span>
<span id="cb34-4"><a href="#cb34-4"></a><span class="op">}</span>;</span>
<span id="cb34-5"><a href="#cb34-5"></a><span class="dt">int</span> score <span class="op">=</span> fold<span class="op">(</span>zip<span class="op">(</span>squares, letters<span class="op">)</span>, Accum<span class="op">()</span>, <span class="op">[](</span>Accum a, <span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;</span> sq_let<span class="op">){</span></span>
<span id="cb34-6"><a href="#cb34-6"></a>        <span class="kw">auto</span> <span class="op">[</span>sq, letter<span class="op">]</span> <span class="op">=</span> sq_letter;</span>
<span id="cb34-7"><a href="#cb34-7"></a>        <span class="cf">return</span> Accum<span class="op">{</span></span>
<span id="cb34-8"><a href="#cb34-8"></a>            <span class="op">.</span>multiplier <span class="op">=</span> a<span class="op">.</span>multiplier <span class="op">*</span> sq<span class="op">.</span>word_multiplier,</span>
<span id="cb34-9"><a href="#cb34-9"></a>            <span class="op">.</span>total <span class="op">=</span> a<span class="op">.</span>total <span class="op">+</span> sq<span class="op">.</span>letter_multiplier <span class="op">*</span> letter</span>
<span id="cb34-10"><a href="#cb34-10"></a>        <span class="op">}</span>;</span>
<span id="cb34-11"><a href="#cb34-11"></a>    <span class="op">}).</span>result<span class="op">()</span>;</span></code></pre></div>
<p>We’re not trying to argue that the second solution is necessarily better than the first - merely that it is a perfectly adequate solution, that happens to not be able to meet the constraints as laid out in P1813.</p>
<p>Instead, we suggest a much lighter set of restrictions on <code class="sourceCode cpp">fold</code>: simply that this is a binary operation:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F, <span class="kw">class</span> T, <span class="kw">class</span> U<span class="op">&gt;</span></span>
<span id="cb35-2"><a href="#cb35-2"></a><span class="kw">concept</span> <em>foldable</em> <span class="op">=</span></span>
<span id="cb35-3"><a href="#cb35-3"></a>    regular_invocable<span class="op">&lt;</span>F<span class="op">&amp;</span>, T, U<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb35-4"><a href="#cb35-4"></a>    convertible_to<span class="op">&lt;</span>invoke_result_t<span class="op">&lt;</span>F<span class="op">&amp;</span>, T, U<span class="op">&gt;</span>, T<span class="op">&gt;</span>;</span>
<span id="cb35-5"><a href="#cb35-5"></a></span>
<span id="cb35-6"><a href="#cb35-6"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F, <span class="kw">class</span> T, <span class="kw">class</span> I<span class="op">&gt;</span></span>
<span id="cb35-7"><a href="#cb35-7"></a><span class="kw">concept</span> <em>indirectly-binary-foldable</em> <span class="op">=</span></span>
<span id="cb35-8"><a href="#cb35-8"></a>    indirectly_readable<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb35-9"><a href="#cb35-9"></a>    copy_constructible<span class="op">&lt;</span>F<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb35-10"><a href="#cb35-10"></a>    <em>foldable</em><span class="op">&lt;</span>F, T, iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb35-11"><a href="#cb35-11"></a>    <em>foldable</em><span class="op">&lt;</span>F, T, iter_reference_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb35-12"><a href="#cb35-12"></a>    <em>foldable</em><span class="op">&lt;</span>F, T, iter_common_reference_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span>;</span>
<span id="cb35-13"><a href="#cb35-13"></a></span>
<span id="cb35-14"><a href="#cb35-14"></a><span class="kw">template</span> <span class="op">&lt;</span>input_range R, movable T, <span class="kw">class</span> Proj <span class="op">=</span> identity, </span>
<span id="cb35-15"><a href="#cb35-15"></a>    <em>indirectly-binary-foldable</em><span class="op">&lt;</span>T, projected<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, Proj<span class="op">&gt;&gt;</span> BinaryOperation<span class="op">&gt;</span></span>
<span id="cb35-16"><a href="#cb35-16"></a><span class="kw">constexpr</span> T fold<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, T init, BinaryOperation op, Proj proj <span class="op">=</span> <span class="op">{})</span> <span class="op">{</span></span>
<span id="cb35-17"><a href="#cb35-17"></a>    range_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> b <span class="op">=</span> begin<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb35-18"><a href="#cb35-18"></a>    range_sentinel_t<span class="op">&lt;</span>R<span class="op">&gt;</span> e <span class="op">=</span> end<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb35-19"><a href="#cb35-19"></a>    <span class="cf">for</span> <span class="op">(</span>; b <span class="op">!=</span> e; <span class="op">++</span>b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb35-20"><a href="#cb35-20"></a>        init <span class="op">=</span> op<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>init<span class="op">)</span>, proj<span class="op">(*</span>b<span class="op">))</span>;</span>
<span id="cb35-21"><a href="#cb35-21"></a>    <span class="op">}</span></span>
<span id="cb35-22"><a href="#cb35-22"></a>    <span class="cf">return</span> init;</span>
<span id="cb35-23"><a href="#cb35-23"></a><span class="op">}</span></span></code></pre></div>
<p>For more on this fold, along with several other fold algorithms, see <span class="citation" data-cites="P2322R4">[<a href="#ref-P2322R4" role="doc-biblioref">P2322R4</a>]</span>.</p>
<h3 data-number="5.1.2" id="rangesreduce"><span class="header-section-number">5.1.2</span> <code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code><a href="#rangesreduce" class="self-link"></a></h3>
<p>We have this interesting situation in the standard library today where <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> has a name strongly suggestive of addition, yet because it’s specified to invoke its binary operation serially, it has no additional requirements on that operation. But we also have <code class="sourceCode cpp">std<span class="op">::</span>reduce</code>, which is a much more generic name with no suggested underlying operation, yet has very strong semantic constraints on its operation: it must be both associative and commutative. This comes from <span class="citation" data-cites="N3408">[<a href="#ref-N3408" role="doc-biblioref">N3408</a>]</span>, emphasis ours:</p>
<div class="quote">
<p>Thrust has no <code class="sourceCode cpp">accumulate</code> algorithm. Instead, it introduces the analogous <code class="sourceCode cpp">thrust<span class="op">::</span>reduce</code>, <strong>which requires stricter semantics from its user-specified sum operator to allow a parallel implementation</strong>. Specifically, <code class="sourceCode cpp">thrust<span class="op">::</span>reduce</code> requires mathematical associativity and commutativity of its user-specified sum operator. This allows the algorithm implementor discretion to parallelize the sum. We chose the name <code class="sourceCode cpp">reduce</code> for this algorithm because we believe that most existing parallel programmers are familiar with the idea of a parallel reduction. Other names for this algorithm exist, e.g., <code class="sourceCode cpp">fold</code>. However,we did not select a name derived from <code class="sourceCode cpp">fold</code> because other languages tend to impose a non-associative directionality to the operation. [cf. Haskell’s <code class="sourceCode cpp">foldl</code> &amp; <code class="sourceCode cpp">foldr</code>, Scala’s <code class="sourceCode cpp">foldLeft</code> &amp; <code class="sourceCode cpp">foldRight</code>]</p>
</div>
<p>While <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> should have minimal constraints, that is not the case for a future <code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code>. As with <code class="sourceCode cpp">std<span class="op">::</span>reduce</code>, we would need to enforce that the binary operation is both associative and commutative. This calls for the kinds of constrains that <span class="citation" data-cites="P1813R0">[<a href="#ref-P1813R0" role="doc-biblioref">P1813R0</a>]</span> is proposing. As it is a more complex set of constraints, we suggest that this is a <span class="yellow">Tier 2 algorithm</span>, with no default operation. Given the previous suggestion of <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> not having a default operation either, we also suggest the addition of a <span class="yellow"><code class="sourceCode cpp">ranges<span class="op">::</span>sum</code> and a <code class="sourceCode cpp">ranges<span class="op">::</span>product</code></span> that simply invoke <code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code> with <code class="sourceCode cpp">std<span class="op">::</span>plus<span class="op">()</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>multiplies<span class="op">()</span></code>, respectively, with an initial value defaulted to <code class="sourceCode cpp">range_value_t<span class="op">&lt;</span>R<span class="op">&gt;()</span></code> and <code class="sourceCode cpp">range_value_t<span class="op">&lt;</span>R<span class="op">&gt;{</span><span class="dv">1</span><span class="op">}</span></code>, respectively.</p>
<p>The naming here is somewhat problematic. <code class="sourceCode cpp">reduce</code> is, in general, a much better name than <code class="sourceCode cpp">accumulate</code> as it does not have any particular operation connotation. But it has additional requirements on the operation. With the suggested change in name, we would end up having both <code class="sourceCode cpp">fold</code> and <code class="sourceCode cpp">reduce</code> — names that seem synonymous and interchangeable, though they are not. We feel that this is probably okay though, since people already frequently think <code class="sourceCode cpp">reduce</code> is “just” the parallel version of <code class="sourceCode cpp">accumulate</code> and perhaps having <code class="sourceCode cpp">fold</code> and <code class="sourceCode cpp">reduce</code> both would make users more likely to consult the documentation?</p>
<h3 data-number="5.1.3" id="rangestransform_reduce-and-rangesinner_product"><span class="header-section-number">5.1.3</span> <code class="sourceCode cpp">ranges<span class="op">::</span>transform_reduce</code> and <code class="sourceCode cpp">ranges<span class="op">::</span>inner_product</code><a href="#rangestransform_reduce-and-rangesinner_product" class="self-link"></a></h3>
<p>These two algorithms are different from the previous two in that they are less fundamental. <code class="sourceCode cpp">transform_reduce</code> is a binary <code class="sourceCode cpp">transform</code> followed by <code class="sourceCode cpp">reduce</code> while <code class="sourceCode cpp">inner_product</code> is a binary <code class="sourceCode cpp">transform</code> followed by <code class="sourceCode cpp">accumulate</code>. First, <code class="sourceCode cpp">inner_product</code>, much like <code class="sourceCode cpp">accumulate</code>, is a bad name for the algorithm as it strongly prejudices <code class="sourceCode cpp">product</code> as the binary transform operation and as such uses of the algorithm with any other function simply look bizarre. From the <a href="https://en.cppreference.com/w/cpp/algorithm/inner_product">cppreference example for <code class="sourceCode cpp">inner_product</code></a>:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1"></a><span class="pp">#include </span><span class="im">&lt;numeric&gt;</span></span>
<span id="cb36-2"><a href="#cb36-2"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb36-3"><a href="#cb36-3"></a><span class="pp">#include </span><span class="im">&lt;vector&gt;</span></span>
<span id="cb36-4"><a href="#cb36-4"></a><span class="pp">#include </span><span class="im">&lt;functional&gt;</span></span>
<span id="cb36-5"><a href="#cb36-5"></a><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb36-6"><a href="#cb36-6"></a><span class="op">{</span></span>
<span id="cb36-7"><a href="#cb36-7"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> a<span class="op">{</span><span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span><span class="op">}</span>;</span>
<span id="cb36-8"><a href="#cb36-8"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> b<span class="op">{</span><span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">1</span><span class="op">}</span>;</span>
<span id="cb36-9"><a href="#cb36-9"></a> </span>
<span id="cb36-10"><a href="#cb36-10"></a>    <span class="dt">int</span> r1 <span class="op">=</span> std<span class="op">::</span>inner_product<span class="op">(</span>a<span class="op">.</span>begin<span class="op">()</span>, a<span class="op">.</span>end<span class="op">()</span>, b<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb36-11"><a href="#cb36-11"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Inner product of a and b: &quot;</span> <span class="op">&lt;&lt;</span> r1 <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb36-12"><a href="#cb36-12"></a> </span>
<span id="cb36-13"><a href="#cb36-13"></a>    <span class="dt">int</span> r2 <span class="op">=</span> std<span class="op">::</span>inner_product<span class="op">(</span>a<span class="op">.</span>begin<span class="op">()</span>, a<span class="op">.</span>end<span class="op">()</span>, b<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">0</span>,</span>
<span id="cb36-14"><a href="#cb36-14"></a>                                std<span class="op">::</span>plus<span class="op">&lt;&gt;()</span>, std<span class="op">::</span>equal_to<span class="op">&lt;&gt;())</span>;</span>
<span id="cb36-15"><a href="#cb36-15"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;Number of pairwise matches between a and b: &quot;</span> <span class="op">&lt;&lt;</span>  r2 <span class="op">&lt;&lt;</span> <span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span>;</span>
<span id="cb36-16"><a href="#cb36-16"></a><span class="op">}</span></span></code></pre></div>
<p>Second, and more importantly, with Ranges allowing us to compose algorithms properly, do we even need these at all? Consider again the above example and how it might be written with and without specialized algorithms:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Specialized</strong>
</div></th>
<th><div style="text-align:center">
<strong>Composed</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1"></a>ranges<span class="op">::</span>inner_product<span class="op">(</span>a, b, <span class="dv">0</span>,</span>
<span id="cb37-2"><a href="#cb37-2"></a>    std<span class="op">::</span>plus<span class="op">()</span>, std<span class="op">::</span>equal_to<span class="op">())</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1"></a>ranges<span class="op">::</span>fold<span class="op">(</span>views<span class="op">::</span>zip_transform<span class="op">(</span>std<span class="op">::</span>equal_to<span class="op">()</span>, a, b<span class="op">)</span>,</span>
<span id="cb38-2"><a href="#cb38-2"></a>    <span class="dv">0</span>, std<span class="op">::</span>plus<span class="op">())</span>;</span>
<span id="cb38-3"><a href="#cb38-3"></a>ranges<span class="op">::</span>sum<span class="op">(</span>views<span class="op">::</span>zip_transform<span class="op">(</span>std<span class="op">::</span>equal_to<span class="op">()</span>, a, b<span class="op">))</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>Even though the <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> construction is more complicated, it’s also easier to see the groupings and understand what’s going on. The composed construction also allows for arbitrarily many ranges, not simply two.</p>
<p>There is also the question of projections. With <code class="sourceCode cpp">transform_reduce</code> and <code class="sourceCode cpp">inner_product</code>, there are <em>three</em> ranges that could be projected: each range into the binary grouping operation, and the result of that grouping. This makes it exceedingly awkward if you only want to provide exactly one of those projections:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Specialized</strong>
</div></th>
<th><div style="text-align:center">
<strong>Composed</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1"></a>ranges<span class="op">::</span>inner_product<span class="op">(</span>a, b, <span class="dv">0</span>,</span>
<span id="cb39-2"><a href="#cb39-2"></a>    std<span class="op">::</span>plus<span class="op">()</span>, std<span class="op">::</span>multiplies<span class="op">()</span>,</span>
<span id="cb39-3"><a href="#cb39-3"></a>    p1<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1"></a>ranges<span class="op">::</span>fold<span class="op">(</span>views<span class="op">::</span>zip_transform<span class="op">(</span>std<span class="op">::</span>multiplies<span class="op">()</span>,</span>
<span id="cb40-2"><a href="#cb40-2"></a>        a <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>p1<span class="op">)</span>, b<span class="op">)</span>,</span>
<span id="cb40-3"><a href="#cb40-3"></a>    <span class="dv">0</span>, std<span class="op">::</span>plus<span class="op">())</span>;</span></code></pre></div></td>
</tr>
<tr class="even">
<td><div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1"></a>ranges<span class="op">::</span>inner_product<span class="op">(</span>a, b, <span class="dv">0</span>,</span>
<span id="cb41-2"><a href="#cb41-2"></a>    std<span class="op">::</span>plus<span class="op">()</span>, std<span class="op">::</span>multiplies<span class="op">()</span>,</span>
<span id="cb41-3"><a href="#cb41-3"></a>    <span class="op">{}</span>, p2<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1"></a>ranges<span class="op">::</span>fold<span class="op">(</span>views<span class="op">::</span>zip_transform<span class="op">(</span>std<span class="op">::</span>multiplies<span class="op">()</span>,</span>
<span id="cb42-2"><a href="#cb42-2"></a>        a, b <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>p2<span class="op">))</span>,</span>
<span id="cb42-3"><a href="#cb42-3"></a>    <span class="dv">0</span>, std<span class="op">::</span>plus<span class="op">())</span>;</span></code></pre></div></td>
</tr>
<tr class="odd">
<td><div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1"></a>ranges<span class="op">::</span>inner_product<span class="op">(</span>a, b, <span class="dv">0</span>,</span>
<span id="cb43-2"><a href="#cb43-2"></a>    std<span class="op">::</span>plus<span class="op">()</span>, std<span class="op">::</span>multiplies<span class="op">()</span>,</span>
<span id="cb43-3"><a href="#cb43-3"></a>    <span class="op">{}</span>, <span class="op">{}</span>, p3<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1"></a>ranges<span class="op">::</span>fold<span class="op">(</span>views<span class="op">::</span>zip_transform<span class="op">(</span>std<span class="op">::</span>multiplies<span class="op">()</span>, a, b<span class="op">)</span></span>
<span id="cb44-2"><a href="#cb44-2"></a>           <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>p3<span class="op">)</span>,</span>
<span id="cb44-3"><a href="#cb44-3"></a>    <span class="dv">0</span>, std<span class="op">::</span>plus<span class="op">())</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>We think that once we add <span class="addu"><code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> as Tier 1 <span class="citation" data-cites="P2322R2">[<a href="#ref-P2322R2" role="doc-biblioref">P2322R2</a>]</span></span> and <span class="yellow"><code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code> as Tier 2</span>, we do not actually have a need for either a <code class="sourceCode cpp">ranges<span class="op">::</span>transform_reduce</code> or a <code class="sourceCode cpp">ranges<span class="op">::</span>inner_product</code> (which would also save us from having to come up with a name for the latter).</p>
<h2 data-number="5.2" id="algorithms-that-output-a-range-anamorphisms"><span class="header-section-number">5.2</span> Algorithms that Output a Range (Anamorphisms)<a href="#algorithms-that-output-a-range-anamorphisms" class="self-link"></a></h2>
<p><code class="sourceCode cpp">iota</code> is the easiest one to consider here. We already have <code class="sourceCode cpp">views<span class="op">::</span>iota</code> in C++20, which importantly means that we already have all the correct constraints in place. In that sense, it almost takes less time to adopt <code class="sourceCode cpp">ranges<span class="op">::</span>iota</code> than it would take to discuss whether or not it’s worth spending time adopting it.</p>
<p>But that does not hold for the other algorithms.</p>
<h3 data-number="5.2.1" id="shift_left-and-shift_right"><span class="header-section-number">5.2.1</span> <code class="sourceCode cpp">shift_left</code> and <code class="sourceCode cpp">shift_right</code><a href="#shift_left-and-shift_right" class="self-link"></a></h3>
<p><code class="sourceCode cpp">shift_left</code> and <code class="sourceCode cpp">shift_right</code> fall into a similar boat as <code class="sourceCode cpp">iota</code>, but aren’t completely without questions. <span class="citation" data-cites="P1243R4">[<a href="#ref-P1243R4" role="doc-biblioref">P1243R4</a>]</span> originally proposed these, but were dropped from the paper based on discussion about the return type. <code class="sourceCode cpp">shift_right</code> has a straightforward return type of <code class="sourceCode cpp">subrange<span class="op">(</span>new_first, last<span class="op">)</span></code>. But what should <code class="sourceCode cpp">shift_left</code> return?</p>
<p>If, for consistency, it returns <code class="sourceCode cpp">subrange<span class="op">(</span>first, new_last<span class="op">)</span></code> then we don’t return <code class="sourceCode cpp">last</code> — even though we probably had to to compute it, unlike most of the other <code class="sourceCode cpp">ranges</code> algorithms. Most, but not all (<code class="sourceCode cpp">is_sorted</code>, <code class="sourceCode cpp">count</code>, and the proposed <code class="sourceCode cpp">fold</code> do not, for instance). Also, if <code class="sourceCode cpp">n <span class="op">==</span> <span class="dv">0</span></code> or <code class="sourceCode cpp">n <span class="op">&gt;=</span> last <span class="op">-</span> first</code>, then <code class="sourceCode cpp">shift_left<span class="op">(</span>r, n<span class="op">)</span></code> does nothing - so should it just return <code class="sourceCode cpp">subrange<span class="op">(</span>first, first<span class="op">)</span></code>? That question will still have to be answered.</p>
<h3 data-number="5.2.2" id="stdadjacent_difference-rangesadjacent_transform"><span class="header-section-number">5.2.2</span> <code class="sourceCode cpp">std<span class="op">::</span>adjacent_difference</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>adjacent_transform</code><a href="#stdadjacent_difference-rangesadjacent_transform" class="self-link"></a></h3>
<p><code class="sourceCode cpp">std<span class="op">::</span>adjacent_difference</code> joins <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> and <code class="sourceCode cpp">std<span class="op">::</span>inner_product</code> in the list of algorithms prejudicially named after a specific operation. We do not yet have <code class="sourceCode cpp">views<span class="op">::</span>adjacent_transform</code> (<span class="addu">Tier 1</span> above), and this would be the algorithm version of those views:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Specialized</strong>
</div></th>
<th><div style="text-align:center">
<strong>Composed</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1"></a>ranges<span class="op">::</span>adjacent_difference<span class="op">(</span>r, o<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1"></a>ranges<span class="op">::</span>copy<span class="op">(</span>views<span class="op">::</span>adjacent_transform<span class="op">(</span>r, std<span class="op">::</span>minus<span class="op">())</span>, o<span class="op">)</span>;</span></code></pre></div></td>
</tr>
<tr class="even">
<td><div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1"></a>ranges<span class="op">::</span>adjacent_difference<span class="op">(</span>r, o, f<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1"></a>ranges<span class="op">::</span>copy<span class="op">(</span>views<span class="op">::</span>adjacent_transform<span class="op">(</span>r, f<span class="op">)</span>, o<span class="op">)</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>Even though we’re increasing the length of the expression as we go, and arguably increasing the complexity of the construction as well, we’re also lowering the surface area of the API by taking advantage of composition. These become even better with the adoption of the pipeline operator in <span class="citation" data-cites="P2011R1">[<a href="#ref-P2011R1" role="doc-biblioref">P2011R1</a>]</span>:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Specialized</strong>
</div></th>
<th><div style="text-align:center">
<strong>Composed</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1"></a>ranges<span class="op">::</span>adjacent_difference<span class="op">(</span>r, o<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1"></a>views<span class="op">::</span>adjacent_transform<span class="op">(</span>r, std<span class="op">::</span>minus<span class="op">())</span> <span class="op">|&gt;</span> ranges<span class="op">::</span>copy<span class="op">(</span>o<span class="op">)</span>;</span></code></pre></div></td>
</tr>
<tr class="even">
<td><div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1"></a>ranges<span class="op">::</span>adjacent_difference<span class="op">(</span>r, o, f<span class="op">)</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1"></a>views<span class="op">::</span>adjacent_transform<span class="op">(</span>r, f<span class="op">)</span> <span class="op">|&gt;</span> ranges<span class="op">::</span>copy<span class="op">(</span>o<span class="op">)</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>This begs the question: do we actually need to have a <code class="sourceCode cpp">ranges<span class="op">::</span>adjacent_transform</code> at all? This question needs to be answered, and its existence lowers the priority of the range-ification of such algorithms relative to the adoption of their corresponding range adapters.</p>
<h3 data-number="5.2.3" id="stdpartial_sum-rangespartial_fold-and-stdinexclusive_scan"><span class="header-section-number">5.2.3</span> <code class="sourceCode cpp">std<span class="op">::</span>partial_sum</code> → <code class="sourceCode cpp">ranges<span class="op">::</span>partial_fold</code> and <code class="sourceCode cpp">std<span class="op">::{</span>in,ex<span class="op">}</span>clusive_scan</code><a href="#stdpartial_sum-rangespartial_fold-and-stdinexclusive_scan" class="self-link"></a></h3>
<p>We saw in the catamorphism section that we have a pair of algorithms, <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> and <code class="sourceCode cpp">std<span class="op">::</span>reduce</code>, that solve basically the same problem except that one prejudices a particular operation (<code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> suggests <code class="sourceCode cpp"><span class="op">+</span></code>) while the other has the more generic name yet is actually more restrictive (<code class="sourceCode cpp">std<span class="op">::</span>reduce</code> requires both the operation to be both associative and commutative, <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> does not require either).</p>
<p>We have the exact same issue here, <code class="sourceCode cpp">std<span class="op">::</span>partial_sum</code> is strongly suggestive of <code class="sourceCode cpp"><span class="op">+</span></code>, while <code class="sourceCode cpp">std<span class="op">::</span>inclusive_scan</code> is the more generically-named algorithm that nevertheless imposes the stronger restriction (in this case, just associativity).</p>
<p>Our suggestion for what to do with <code class="sourceCode cpp">std<span class="op">::</span>partial_sum</code> and <code class="sourceCode cpp">std<span class="op">::{</span>in,ex<span class="op">}</span>clusive_scan</code> thus mirrors our suggestion for what we did with <code class="sourceCode cpp">std<span class="op">::</span>accumulate</code> and <code class="sourceCode cpp">std<span class="op">::</span>reduce</code>:</p>
<ul>
<li>rename <code class="sourceCode cpp">std<span class="op">::</span>partial_sum</code> to <code class="sourceCode cpp">ranges<span class="op">::</span>partial_fold</code> (since it’s a <code class="sourceCode cpp">fold</code> that also yields partial results), which will have neither a defaulted binary operation nor associativity requirements.</li>
<li>introduce <code class="sourceCode cpp">ranges<span class="op">::{</span>in,ex<span class="op">}</span>clusive_scan</code></li>
<li>introduce <code class="sourceCode cpp">ranges<span class="op">::</span>partial_sum</code> that is hard-coded to use <code class="sourceCode cpp">std<span class="op">::</span>plus<span class="op">()</span></code> as the binary operation, which internally forwards to <code class="sourceCode cpp">ranges<span class="op">::</span>inclusive_scan</code> (not <code class="sourceCode cpp">ranges<span class="op">::</span>partial_fold</code>, since we know addition is associative).</li>
</ul>
<p>As we discussed with the question of the need for <code class="sourceCode cpp">adjacent_difference</code>, there would also be the question of whether we need these algorithms at all. As such, we ascribe them fairly low priority.</p>
<h3 data-number="5.2.4" id="transform_inexclusive_scan"><span class="header-section-number">5.2.4</span> <code class="sourceCode cpp">transform_<span class="op">{</span>in,ex<span class="op">}</span>clusive_scan</code><a href="#transform_inexclusive_scan" class="self-link"></a></h3>
<p>Similar to the question of <code class="sourceCode cpp">transform_reduce</code> and <code class="sourceCode cpp">inner_product</code>, we don’t think we need a:</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1"></a>ranges<span class="op">::</span>transform_inclusive_scan<span class="op">(</span>r, o, f, g<span class="op">)</span>;</span></code></pre></div>
<p>once we can write</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1"></a>ranges<span class="op">::</span>inclusive_scan<span class="op">(</span>r <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>g<span class="op">)</span>, o, f<span class="op">)</span>;</span></code></pre></div>
<p>or even</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1"></a>ranges<span class="op">::</span>copy<span class="op">(</span>r <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>g<span class="op">)</span> <span class="op">|</span> views<span class="op">::</span>inclusive_scan<span class="op">(</span>f<span class="op">)</span>, o<span class="op">)</span>;</span></code></pre></div>
<p>The latter two having the nice property that you don’t have to remember the order of operations of the operations. We don’t think we need these at all.</p>
<h2 data-number="5.3" id="parallel-algorithms"><span class="header-section-number">5.3</span> Parallel Algorithms<a href="#parallel-algorithms" class="self-link"></a></h2>
<p>One of the C++17 additions was the introduction of the parallel algorithms by way of the Parallelism TS <span class="citation" data-cites="P0024R2">[<a href="#ref-P0024R2" role="doc-biblioref">P0024R2</a>]</span>. But with Ranges, we don’t have parallel overloads of any of the algorithms yet. How should we prioritize adding parallel overloads for the range algorithms?</p>
<p>The most important issue to consider is: with all the ongoing work on executors, we very much want to ensure that the parallel overloads we define will end up working. The status quo in the standard library is that the <code class="sourceCode cpp">ExecutionPolicy</code> parameter is constrained on <code class="sourceCode cpp">is_execution_policy_v<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>ExecutionPolicy<span class="op">&gt;&gt;</span></code>. Is that good enough for executors? It might not be, and it would be extremely disappointing to adopt executors in a way that is incompatible with a bunch of parallel algorithms we just added. This needs careful consideration by somebody familiar with executors.</p>
<p>The second issue is that there are additional requirements imposed on the parallel overloads as compared to the sequential ones (see <span>25.3 <a href="https://wg21.link/algorithms.parallel">[algorithms.parallel]</a></span> as well as <span class="citation" data-cites="P0836R1">[<a href="#ref-P0836R1" role="doc-biblioref">P0836R1</a>]</span>). Those requirements would need to be somehow captured in concepts. Even if the type trait is considered sufficient for executors going forward, the concepts work is still necessary.</p>
<p>And for those algorithms which we do not yet have range-based overloads, we still have exactly the same issue for why we don’t have range-based overloads yet: what are the concepts that we need to constrain the various parameters?</p>
<p>Due to the executor dependency and the need to be careful about specifying the concepts for parallel requirements, we consider this Tier 2.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="actions"><span class="header-section-number">6</span> Actions<a href="#actions" class="self-link"></a></h1>
<p>There are really three kinds of operations that exist in range-v3:</p>
<ul>
<li>Algorithms are operations that eagerly either mutate an input range (e.g. <code class="sourceCode cpp">sort</code>), produce a value (e.g. <code class="sourceCode cpp">max_element</code>), both (<code class="sourceCode cpp">partition</code>), or produce a new range by way of an output iterator or output range (e.g. <code class="sourceCode cpp">copy</code>).</li>
<li>Views are operations that lazily produce a new range.</li>
<li>Actions are operations that eagerly produce a new range.</li>
</ul>
<p>While we have range-based algorithms and views in C++20, we do not yet have any actions. range-v3 comes with many actions, some of which are the action flavor of views and some of which are the action flavor of algorithms. The full list is: <code class="sourceCode cpp">drop</code>, <code class="sourceCode cpp">drop_while</code>, <code class="sourceCode cpp">erase</code>, <code class="sourceCode cpp">insert</code>, <code class="sourceCode cpp">join</code>, <code class="sourceCode cpp">push_back</code>, <code class="sourceCode cpp">push_front</code>, <code class="sourceCode cpp">remove_if</code>, <code class="sourceCode cpp">remove</code>, <code class="sourceCode cpp">reverse</code>, <code class="sourceCode cpp">shuffle</code>, <code class="sourceCode cpp">slice</code>, <code class="sourceCode cpp">sort</code>, <code class="sourceCode cpp">split</code>, <code class="sourceCode cpp">stable_sort</code>, <code class="sourceCode cpp">stride</code>, <code class="sourceCode cpp">take</code>, <code class="sourceCode cpp">take_while</code>, <code class="sourceCode cpp">transform</code>, <code class="sourceCode cpp">unique</code>, and <code class="sourceCode cpp">unstable_remove_if</code>.</p>
<p>The advantage of these actions is that unlike the algorithms, they compose, and unlike the views, you can pass rvalue ranges to them. From the examples in the range-v3 documentation <span class="citation" data-cites="range-v3.docs">[<a href="#ref-range-v3.docs" role="doc-biblioref">range-v3.docs</a>]</span>:</p>
<div class="quote">
<p>When you want to mutate a container in-place, or forward it through a chain of mutating operations, you can use actions. The following examples should make it clear.</p>
<p>Read data into a vector, sort it, and make it unique.</p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1"></a><span class="kw">extern</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> read_data<span class="op">()</span>;</span>
<span id="cb56-2"><a href="#cb56-2"></a><span class="kw">using</span> <span class="kw">namespace</span> ranges;</span>
<span id="cb56-3"><a href="#cb56-3"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> vi <span class="op">=</span> read_data<span class="op">()</span> <span class="op">|</span> actions<span class="op">::</span>sort <span class="op">|</span> actions<span class="op">::</span>unique;</span></code></pre></div>
<p>Do the same to a vector that already contains some data:</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1"></a>vi <span class="op">=</span> std<span class="op">::</span>move<span class="op">(</span>vi<span class="op">)</span> <span class="op">|</span> actions<span class="op">::</span>sort <span class="op">|</span> actions<span class="op">::</span>unique;</span></code></pre></div>
<p>Mutate the container in-place:</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1"></a>vi <span class="op">|=</span> actions<span class="op">::</span>sort <span class="op">|</span> actions<span class="op">::</span>unique;</span></code></pre></div>
<p>Same as above, but with function-call syntax instead of pipe syntax:</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1"></a>actions<span class="op">::</span>unique<span class="op">(</span>actions<span class="op">::</span>sort<span class="op">(</span>vi<span class="op">))</span>;</span></code></pre></div>
</div>
<p>Indeed, ranges actions do seem very useful — and provide the ability to pipeline operations that we cannot do today. There is, nor will there ever be, a <code class="sourceCode cpp">views<span class="op">::</span>sort</code>, so the only option today is:</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> vi <span class="op">=</span> read_data<span class="op">()</span>;</span>
<span id="cb60-2"><a href="#cb60-2"></a>ranges<span class="op">::</span>sort<span class="op">(</span>vi<span class="op">)</span>;</span>
<span id="cb60-3"><a href="#cb60-3"></a>ranges<span class="op">::</span>unique<span class="op">(</span>vi<span class="op">)</span>;</span></code></pre></div>
<p>But while it might be nicer to provide a pipeline approach, we feel this whole space simply needs more research. It is an immediate source of frustration for users when they discover that while you can pipe a <code class="sourceCode cpp">view</code> into an <code class="sourceCode cpp">action</code>, you cannot do the reverse.</p>
<p>Given that the actions don’t provide any functionality that we don’t already have, simply adding the ability to compose some operations better, we give them pretty low priority relative to the wealth of new functionality many of the other operations here provide.</p>
<h1 data-number="7" style="border-bottom:1px solid #cccccc" id="plan-summary"><span class="header-section-number">7</span> Plan Summary<a href="#plan-summary" class="self-link"></a></h1>
<p>To summarize the above descriptions, we want to triage a lot of outstanding ranges algorithms, views, actions, and other utilities into three tiers based on our opinions of their importance. While ideally we could just add everything into C++23, we realize that this is not realistic with the amount of available LWG bandwidth, so our tier 1 here is trying to be as small as possible while still hitting as many major pain points as possible.</p>
<p>The following includes links ot papers that currently exist so far.</p>
<h2 data-number="7.1" id="tier-1"><span class="header-section-number">7.1</span> <span class="addu">Tier 1</span><a href="#tier-1" class="self-link"></a></h2>
<ul>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>to</code> (<span class="citation" data-cites="P1206R6">[<a href="#ref-P1206R6" role="doc-biblioref">P1206R6</a>]</span>)</li>
<li>the ability for user-defined range adaptors to properly cooperate with standard library ones (<span class="citation" data-cites="P2387R1">[<a href="#ref-P2387R1" role="doc-biblioref">P2387R1</a>]</span>)</li>
<li>the ability to format ranges with <code class="sourceCode cpp">std<span class="op">::</span>format</code> (<span class="citation" data-cites="P2286R2">[<a href="#ref-P2286R2" role="doc-biblioref">P2286R2</a>]</span>)</li>
<li>the addition of the following range adapters:
<ul>
<li><code class="sourceCode cpp">views<span class="op">::</span>adjacent</code> (<span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>adjacent_transform</code> (<span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>as_const</code> (<span class="citation" data-cites="P2278R1">[<a href="#ref-P2278R1" role="doc-biblioref">P2278R1</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>cartesian_product</code> (<span class="citation" data-cites="P2374R1">[<a href="#ref-P2374R1" role="doc-biblioref">P2374R1</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>chunk</code> (<span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>chunk_by</code> (<span class="citation" data-cites="P2443R0">[<a href="#ref-P2443R0" role="doc-biblioref">P2443R0</a>]</span>)<br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>enumerate</code> (<span class="citation" data-cites="P2164R5">[<a href="#ref-P2164R5" role="doc-biblioref">P2164R5</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>join_with</code> (<span class="citation" data-cites="P2441R0">[<a href="#ref-P2441R0" role="doc-biblioref">P2441R0</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>slide</code> (<span class="citation" data-cites="P2442R0">[<a href="#ref-P2442R0" role="doc-biblioref">P2442R0</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>stride</code> (<span class="citation" data-cites="P1899R0">[<a href="#ref-P1899R0" role="doc-biblioref">P1899R0</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>zip</code> (<span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>)</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>zip_transform</code> (<span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>)</li>
</ul></li>
<li>the addition of the following range algorithms:
<ul>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>iota</code> (<span class="citation" data-cites="P2440R0">[<a href="#ref-P2440R0" role="doc-biblioref">P2440R0</a>]</span>)</li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>fold</code> (<span class="citation" data-cites="P2322R4">[<a href="#ref-P2322R4" role="doc-biblioref">P2322R4</a>]</span>)</li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>shift_left</code> (<span class="citation" data-cites="P2440R0">[<a href="#ref-P2440R0" role="doc-biblioref">P2440R0</a>]</span>)</li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>shift_right</code> (<span class="citation" data-cites="P2440R0">[<a href="#ref-P2440R0" role="doc-biblioref">P2440R0</a>]</span>)</li>
</ul></li>
<li>the following other changes to standard library (necessary for the <code class="sourceCode cpp">zip</code> family, all handled by <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>):
<ul>
<li><code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> should be const-assignable whenever <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">U</code> are both const-assignable</li>
<li><code class="sourceCode cpp">pair<span class="op">&lt;</span>T<span class="op">&amp;</span>, U<span class="op">&amp;&gt;</span></code> should be constructible from <code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;&amp;</span></code></li>
<li><code class="sourceCode cpp">tuple<span class="op">&lt;</span>T<span class="op">...&gt;</span></code> should be const-assignable whenever <code class="sourceCode cpp">T<span class="op">...</span></code> are const-assignable</li>
<li><code class="sourceCode cpp">tuple<span class="op">&lt;</span>T<span class="op">&amp;...&gt;</span></code> should be constructible from <code class="sourceCode cpp">tuple<span class="op">&lt;</span>T<span class="op">...&gt;&amp;</span></code>.</li>
<li><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code> should be const-assignable</li>
</ul></li>
</ul>
<h2 data-number="7.2" id="tier-2"><span class="header-section-number">7.2</span> <span class="yellow">Tier 2</span><a href="#tier-2" class="self-link"></a></h2>
<ul>
<li>the addition of the following range adapters:
<ul>
<li><code class="sourceCode cpp">views<span class="op">::</span>cache1</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>chunk_on</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>concat</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>cycle</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>delimit</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>drop_last</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>drop_last_while</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>generate</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>generate_n</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>group_by_key</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>intersperse</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>partial_sum</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>remove</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>remove_if</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>repeat</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>repeat_n</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>replace</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>replace_if</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>scan</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>split_when</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>take_last</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>take_last_while</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>transform_maybe</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>trim</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>unique</code></li>
</ul></li>
<li>the addition of the following range algorithms:
<ul>
<li>parallel overloads of all the existing algorithms in <code class="sourceCode cpp">std<span class="op">::</span>ranges</code> that have a parallel overload in <code class="sourceCode cpp">std</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>reduce</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>sum</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>product</code></li>
</ul></li>
</ul>
<h2 data-number="7.3" id="tier-3"><span class="header-section-number">7.3</span> <span class="diffdel">Tier 3</span><a href="#tier-3" class="self-link"></a></h2>
<ul>
<li>the addition of the following range adapters:
<ul>
<li><code class="sourceCode cpp">views<span class="op">::</span>adjacent_filter</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>adjacent_remove_if</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>drop_exactly</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>flat_map</code> (possibly unnecessary given <span class="citation" data-cites="P2328R1">[<a href="#ref-P2328R1" role="doc-biblioref">P2328R1</a>]</span>)<br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>head</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>linear_distribute</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>sample</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>set_difference</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>set_intersection</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>set_union</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>set_symmetric_difference</code></li>
<li><code class="sourceCode cpp">views<span class="op">::</span>slice</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>tail</code><br />
</li>
<li><code class="sourceCode cpp">views<span class="op">::</span>take_exactly</code></li>
</ul></li>
<li>the addition of the following range algorithms:
<ul>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>adjacent_transform</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>partial_fold</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>inclusive_scan</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>exclusive_scan</code></li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>partial_sum</code></li>
</ul></li>
<li>the addition of ranges actions</li>
</ul>
<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-haskell.groupby">
<p>[haskell.groupby] Donnacha Oisín Kidney. groupBy: Replacement definition of Data.List.GroupBy. <br />
<a href="https://hackage.haskell.org/package/groupBy">https://hackage.haskell.org/package/groupBy</a></p>
</div>
<div id="ref-hoekstra.cppcon">
<p>[hoekstra.cppcon] Conor Hoekstra. 2019. 23 Ranges: slide &amp; stride. <br />
<a href="https://www.youtube.com/watch?v=-_lqZJK2vjI">https://www.youtube.com/watch?v=-_lqZJK2vjI</a></p>
</div>
<div id="ref-N3408">
<p>[N3408] J. Hoberock, O. Giroux, V. Grover, J. Marathe, et al. 2012-09-21. Parallelizing The Standard Algorithms Library. <br />
<a href="https://wg21.link/n3408">https://wg21.link/n3408</a></p>
</div>
<div id="ref-niebler.iter.0">
<p>[niebler.iter.0] Eric Niebler. 2015. To Be or Not to Be (an Iterator). <br />
<a href="http://ericniebler.com/2015/01/28/to-be-or-not-to-be-an-iterator/">http://ericniebler.com/2015/01/28/to-be-or-not-to-be-an-iterator/</a></p>
</div>
<div id="ref-niebler.iter.1">
<p>[niebler.iter.1] Eric Niebler. 2015. Iterators++, Part 1. <br />
<a href="http://ericniebler.com/2015/02/03/iterators-plus-plus-part-1/">http://ericniebler.com/2015/02/03/iterators-plus-plus-part-1/</a></p>
</div>
<div id="ref-niebler.iter.2">
<p>[niebler.iter.2] Eric Niebler. 2015. Iterators++, Part 2. <br />
<a href="http://ericniebler.com/2015/02/13/iterators-plus-plus-part-2/">http://ericniebler.com/2015/02/13/iterators-plus-plus-part-2/</a></p>
</div>
<div id="ref-niebler.iter.3">
<p>[niebler.iter.3] Eric Niebler. 2015. Iterators++, Part 3. <br />
<a href="http://ericniebler.com/2015/03/03/iterators-plus-plus-part-3/">http://ericniebler.com/2015/03/03/iterators-plus-plus-part-3/</a></p>
</div>
<div id="ref-P0024R2">
<p>[P0024R2] Jared Hoberock. 2016-03-04. The Parallelism TS Should be Standardized. <br />
<a href="https://wg21.link/p0024r2">https://wg21.link/p0024r2</a></p>
</div>
<div id="ref-P0592R4">
<p>[P0592R4] Ville Voutilainen. 2019-11-25. To boldly suggest an overall plan for C++23. <br />
<a href="https://wg21.link/p0592r4">https://wg21.link/p0592r4</a></p>
</div>
<div id="ref-P0836R1">
<p>[P0836R1] Gordon Brown, Christopher Di Bella, Michael Haidl, Toomas Remmelg, Ruyman Reyes, Michel Steuwer, Michael Wong. 2018-05-07. Introduce Parallelism to the Ranges TS. <br />
<a href="https://wg21.link/p0836r1">https://wg21.link/p0836r1</a></p>
</div>
<div id="ref-P0896R4">
<p>[P0896R4] Eric Niebler, Casey Carter, Christopher Di Bella. 2018-11-09. The One Ranges Proposal. <br />
<a href="https://wg21.link/p0896r4">https://wg21.link/p0896r4</a></p>
</div>
<div id="ref-P1206R6">
<p>[P1206R6] Corentin Jabot, Eric Niebler, Casey Carter. 2021-08-03. Conversions from ranges to containers. <br />
<a href="https://wg21.link/p1206r6">https://wg21.link/p1206r6</a></p>
</div>
<div id="ref-P1243R4">
<p>[P1243R4] Dan Raviv. 2020-02-12. Rangify New Algorithms. <br />
<a href="https://wg21.link/p1243r4">https://wg21.link/p1243r4</a></p>
</div>
<div id="ref-P1255R6">
<p>[P1255R6] Steve Downey. 2020-04-05. A view of 0 or 1 elements: views::maybe. <br />
<a href="https://wg21.link/p1255r6">https://wg21.link/p1255r6</a></p>
</div>
<div id="ref-P1522R1">
<p>[P1522R1] Eric Niebler. 2019-07-28. Iterator Difference Type and Integer Overflow. <br />
<a href="https://wg21.link/p1522r1">https://wg21.link/p1522r1</a></p>
</div>
<div id="ref-P1645R1">
<p>[P1645R1] Ben Deane. 2019-05-14. constexpr for numeric algorithms. <br />
<a href="https://wg21.link/p1645r1">https://wg21.link/p1645r1</a></p>
</div>
<div id="ref-P1716R3">
<p>[P1716R3] Tomasz Kamiński. 2019-11-07. ranges compare algorithm are over-constrained. <br />
<a href="https://wg21.link/p1716r3">https://wg21.link/p1716r3</a></p>
</div>
<div id="ref-P1739R4">
<p>[P1739R4] Hannes Hauswedell. 2020-03-01. Avoid template bloat for safe_ranges in combination with “subrange-y” view adaptors. <br />
<a href="https://wg21.link/p1739r4">https://wg21.link/p1739r4</a></p>
</div>
<div id="ref-P1813R0">
<p>[P1813R0] Christopher Di Bella. 2019-08-02. A Concept Design for the Numeric Algorithms. <br />
<a href="https://wg21.link/p1813r0">https://wg21.link/p1813r0</a></p>
</div>
<div id="ref-P1894R0">
<p>[P1894R0] Andrew Tomazos. 2019-10-02. Proposal of std::upto, std::indices and std::enumerate. <br />
<a href="https://wg21.link/p1894r0">https://wg21.link/p1894r0</a></p>
</div>
<div id="ref-P1899R0">
<p>[P1899R0] Christopher Di Bella. 2019-10-07. stride_view. <br />
<a href="https://wg21.link/p1899r0">https://wg21.link/p1899r0</a></p>
</div>
<div id="ref-P2011R1">
<p>[P2011R1] Barry Revzin, Colby Pike. 2020-04-16. A pipeline-rewrite operator. <br />
<a href="https://wg21.link/p2011r1">https://wg21.link/p2011r1</a></p>
</div>
<div id="ref-P2164R5">
<p>[P2164R5] Corentin Jabot. 2021-06-15. views::enumerate. <br />
<a href="https://wg21.link/p2164r5">https://wg21.link/p2164r5</a></p>
</div>
<div id="ref-P2210R0">
<p>[P2210R0] Barry Revzin. 2020-08-14. Superior String Splitting. <br />
<a href="https://wg21.link/p2210r0">https://wg21.link/p2210r0</a></p>
</div>
<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-P2278R1">
<p>[P2278R1] Barry Revzin. 2021. <code class="sourceCode cpp">cbegin</code> should always return a constant iterator. <br />
<a href="https://wg21.link/p2278r1">https://wg21.link/p2278r1</a></p>
</div>
<div id="ref-P2286R2">
<p>[P2286R2] Barry Revzin. 2021-08-16. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r2">https://wg21.link/p2286r2</a></p>
</div>
<div id="ref-P2321R2">
<p>[P2321R2] Tim Song. 2021-06-11. zip. <br />
<a href="https://wg21.link/p2321r2">https://wg21.link/p2321r2</a></p>
</div>
<div id="ref-P2322R2">
<p>[P2322R2] Barry Revzin. 2021-04-15. ranges::fold. <br />
<a href="https://wg21.link/p2322r2">https://wg21.link/p2322r2</a></p>
</div>
<div id="ref-P2322R4">
<p>[P2322R4] Barry Revzin. 2021. <code class="sourceCode cpp">ranges<span class="op">::</span>fold</code>. <br />
<a href="https://wg21.link/p2322r4">https://wg21.link/p2322r4</a></p>
</div>
<div id="ref-P2328R1">
<p>[P2328R1] Tim Song. 2021-05-08. join_view should join all views of ranges. <br />
<a href="https://wg21.link/p2328r1">https://wg21.link/p2328r1</a></p>
</div>
<div id="ref-P2374R1">
<p>[P2374R1] Sy Brand. 2021-05-11. views::cartesian_product. <br />
<a href="https://wg21.link/p2374r1">https://wg21.link/p2374r1</a></p>
</div>
<div id="ref-P2387R1">
<p>[P2387R1] Barry Revzin. 2021-08-14. Pipe support for user-defined range adaptors. <br />
<a href="https://wg21.link/p2387r1">https://wg21.link/p2387r1</a></p>
</div>
<div id="ref-P2440R0">
<p>[P2440R0] Tim Song. 2021. <code class="sourceCode cpp">ranges<span class="op">::</span>iota</code>, <code class="sourceCode cpp">ranges<span class="op">::</span>shift_left</code>, and <code class="sourceCode cpp">ranges<span class="op">::</span>shift_right</code>. <br />
<a href="https://wg21.link/p2440r0">https://wg21.link/p2440r0</a></p>
</div>
<div id="ref-P2441R0">
<p>[P2441R0] Barry Revzin. 2021. <code class="sourceCode cpp">views<span class="op">::</span>join_with</code>. <br />
<a href="https://wg21.link/p2441r0">https://wg21.link/p2441r0</a></p>
</div>
<div id="ref-P2442R0">
<p>[P2442R0] Tim Song. 2021. Windowing range adaptors: <code class="sourceCode cpp">views<span class="op">::</span>chunk</code> and <code class="sourceCode cpp">views<span class="op">::</span>slide</code>. <br />
<a href="https://wg21.link/p2442r0">https://wg21.link/p2442r0</a></p>
</div>
<div id="ref-P2443R0">
<p>[P2443R0] Tim Song. 2021. <code class="sourceCode cpp">views<span class="op">::</span>chunk_by</code>. <br />
<a href="https://wg21.link/p2443r0">https://wg21.link/p2443r0</a></p>
</div>
<div id="ref-range-v3">
<p>[range-v3] Eric Niebler. 2014. range-v3. <br />
<a href="https://github.com/ericniebler/range-v3/">https://github.com/ericniebler/range-v3/</a></p>
</div>
<div id="ref-range-v3.1141">
<p>[range-v3.1141] voivoid. 2019. view::enumerate issues with latest 1.0-beta commits? <br />
<a href="https://github.com/ericniebler/range-v3/issues/1141">https://github.com/ericniebler/range-v3/issues/1141</a></p>
</div>
<div id="ref-range-v3.573">
<p>[range-v3.573] Jarod42. 2017. Readable types with prvalue reference types erroneously model IndirectlyMovable. <br />
<a href="https://github.com/ericniebler/range-v3/issues/573">https://github.com/ericniebler/range-v3/issues/573</a></p>
</div>
<div id="ref-range-v3.docs">
<p>[range-v3.docs] Eric Niebler. 2014. range-v3 documentation. <br />
<a href="https://ericniebler.github.io/range-v3/">https://ericniebler.github.io/range-v3/</a></p>
</div>
<div id="ref-stepanov">
<p>[stepanov] Alexander A. Stepanov. 2014. From Mathematics to Generic Programming. </p>
</div>
<div id="ref-stl2.381">
<p>[stl2.381] Eric Niebler. 2017. Readable types with prvalue reference types erroneously model Writable. <br />
<a href="https://github.com/ericniebler/stl2/issues/381">https://github.com/ericniebler/stl2/issues/381</a></p>
</div>
<div id="ref-swift.algorithms">
<p>[swift.algorithms] Nate Cook. Announcing Swift Algorithms. <br />
<a href="https://swift.org/blog/swift-algorithms/">https://swift.org/blog/swift-algorithms/</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
