<!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="2024-12-29" />
  <title>`any_view`</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 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; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { 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;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center"><code class="sourceCode cpp">any_view</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3411R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-12-29</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG9, LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Hui Xie<br>&lt;<a href="mailto:hui.xie1990@gmail.com" class="email">hui.xie1990@gmail.com</a>&gt;<br>
      Louis Dionne<br>&lt;<a href="mailto:ldionne.2@gmail.com" class="email">ldionne.2@gmail.com</a>&gt;<br>
      S. Levent Yilmaz<br>&lt;<a href="mailto:levent.yilmaz@gmail.com" class="email">levent.yilmaz@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" id="toc-revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a>
<ul>
<li><a href="#r1" id="toc-r1"><span class="toc-section-number">1.1</span> R1<span></span></a></li>
<li><a href="#r0" id="toc-r0"><span class="toc-section-number">1.2</span> R0<span></span></a></li>
</ul></li>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">2</span> Abstract<span></span></a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation<span></span></a></li>
<li><a href="#design-space-and-prior-art" id="toc-design-space-and-prior-art"><span class="toc-section-number">4</span> Design Space and Prior
Art<span></span></a>
<ul>
<li><a href="#boost.range-boostrangesany_range" id="toc-boost.range-boostrangesany_range"><span class="toc-section-number">4.1</span> Boost.Range <code class="sourceCode cpp">boost<span class="op">::</span>ranges<span class="op">::</span>any_range</code><span></span></a></li>
<li><a href="#range-v3-rangesviewsany_view" id="toc-range-v3-rangesviewsany_view"><span class="toc-section-number">4.2</span> range-v3 <code class="sourceCode cpp">ranges<span class="op">::</span>views<span class="op">::</span>any_view</code><span></span></a></li>
</ul></li>
<li><a href="#proposed-design" id="toc-proposed-design"><span class="toc-section-number">5</span> Proposed
Design<span></span></a></li>
<li><a href="#alternative-design-for-template-parameters" id="toc-alternative-design-for-template-parameters"><span class="toc-section-number">6</span> Alternative Design for Template
Parameters<span></span></a>
<ul>
<li><a href="#alternative-design-1-variadic-named-template-parameters" id="toc-alternative-design-1-variadic-named-template-parameters"><span class="toc-section-number">6.1</span> Alternative Design 1: Variadic
Named Template Parameters<span></span></a></li>
<li><a href="#alternative-design-2-single-template-parameter-rangetraits" id="toc-alternative-design-2-single-template-parameter-rangetraits"><span class="toc-section-number">6.2</span> Alternative Design 2: Single
Template Parameter: RangeTraits<span></span></a></li>
<li><a href="#alternative-design-3-barrys-named-template-argument-approach" id="toc-alternative-design-3-barrys-named-template-argument-approach"><span class="toc-section-number">6.3</span> Alternative Design 3: Barry’s
Named Template Argument Approach<span></span></a></li>
</ul></li>
<li><a href="#other-design-considerations" id="toc-other-design-considerations"><span class="toc-section-number">7</span> Other Design
Considerations<span></span></a>
<ul>
<li><a href="#why-dont-follow-range-v3s-design-where-first-template-parameter-is-range_reference_t" id="toc-why-dont-follow-range-v3s-design-where-first-template-parameter-is-range_reference_t"><span class="toc-section-number">7.1</span> Why don’t follow range-v3’s design
where first template parameter is
<code class="sourceCode cpp">range_reference_t</code>?<span></span></a></li>
<li><a href="#name-of-the-any_view_options" id="toc-name-of-the-any_view_options"><span class="toc-section-number">7.2</span> Name of the
<code class="sourceCode cpp">any_view_options</code><span></span></a></li>
<li><a href="#constexpr-support" id="toc-constexpr-support"><span class="toc-section-number">7.3</span>
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
Support<span></span></a></li>
<li><a href="#move-only-view-support" id="toc-move-only-view-support"><span class="toc-section-number">7.4</span> Move-only
<code class="sourceCode cpp">view</code> Support<span></span></a></li>
<li><a href="#move-only-iterator-support" id="toc-move-only-iterator-support"><span class="toc-section-number">7.5</span> Move-only
<code class="sourceCode cpp">iterator</code>
Support<span></span></a></li>
<li><a href="#is-any_view_optionscontiguous-needed" id="toc-is-any_view_optionscontiguous-needed"><span class="toc-section-number">7.6</span> Is <code class="sourceCode cpp">any_view_options<span class="op">::</span>contiguous</code>
Needed ?<span></span></a></li>
<li><a href="#is-any_view-const-iterable" id="toc-is-any_view-const-iterable"><span class="toc-section-number">7.7</span> Is
<code class="sourceCode cpp">any_view</code>
const-iterable?<span></span></a></li>
<li><a href="#common_range-support" id="toc-common_range-support"><span class="toc-section-number">7.8</span>
<code class="sourceCode cpp">common_range</code>
support<span></span></a></li>
<li><a href="#borrowed_range-support" id="toc-borrowed_range-support"><span class="toc-section-number">7.9</span>
<code class="sourceCode cpp">borrowed_range</code>
support<span></span></a></li>
<li><a href="#valueless-state-of-any_view" id="toc-valueless-state-of-any_view"><span class="toc-section-number">7.10</span> Valueless state of
<code class="sourceCode cpp">any_view</code><span></span></a></li>
<li><a href="#abi-stability" id="toc-abi-stability"><span class="toc-section-number">7.11</span> ABI
Stability<span></span></a></li>
<li><a href="#performance" id="toc-performance"><span class="toc-section-number">7.12</span> Performance<span></span></a></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">8</span> Implementation
Experience<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">9</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<h2 data-number="1.1" id="r1"><span class="header-section-number">1.1</span> R1<a href="#r1" class="self-link"></a></h2>
<ul>
<li>Performance tests update
<ul>
<li>All benchmarks use -O3 (as requested in Wrocław)</li>
<li>For eager algorithms, do not use ranges at all (as requested in
Wrocław)</li>
<li>Add a new benchmark test case where
<code class="sourceCode cpp">vector</code> vs
<code class="sourceCode cpp">any_view</code> used in function
arguments</li>
</ul></li>
<li>Template parameters redesign
<ul>
<li><code class="sourceCode cpp">any_view<span class="op">&lt;</span>Foo<span class="op">&gt;</span></code>
and <code class="sourceCode cpp">any_view<span class="op">&lt;</span><span class="kw">const</span> Foo<span class="op">&gt;</span></code>
should just work</li>
<li>4 Different alternative designs</li>
</ul></li>
</ul>
<h2 data-number="1.2" id="r0"><span class="header-section-number">1.2</span> R0<a href="#r0" class="self-link"></a></h2>
<ul>
<li>Initial revision.</li>
</ul>
<h1 data-number="2" id="abstract"><span class="header-section-number">2</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes a new type-erased view: <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>any_view</code>.
That type-erased view allows customizing the traversal category of the
view, its value type and a few other properties. For example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> MyClass <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unordered_map<span class="op">&lt;</span>Key, Widget<span class="op">&gt;</span> widgets_;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>Widget<span class="op">&gt;</span> getWidgets<span class="op">()</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>Widget<span class="op">&gt;</span> MyClass<span class="op">::</span>getWidgets<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> widgets_ <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>values</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>                  <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>filter<span class="op">(</span>myFilter<span class="op">)</span>;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Since being merged into C++20, the Ranges library has gained an
increasingly rich and expressive set of views. For example,</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">// in MyClass.hpp</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> MyClass <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unordered_map<span class="op">&lt;</span>Key, Widget<span class="op">&gt;</span> widgets_;</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> getWidgets<span class="op">()</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> widgets_ <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>values</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>                    <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>filter<span class="op">([](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;){</span> <span class="co">/*...*/</span> <span class="op">})</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>While such use of ranges is exceedingly convenient, it has the
drawback of leaking implementation details into the interface. In this
example, the return type of the function essentially bakes the
implementation of the function into the interface.</p>
<p>In large applications, such liberal use of
<code class="sourceCode cpp">std<span class="op">::</span>ranges</code>
can lead to increased header dependencies and often a significant
compilation time penalty.</p>
<p>Attempts to separate the implementation into its own translation
unit, as is a common practice for non-templated code, are futile in this
situation. The return type of the above definition of
<code class="sourceCode cpp">getWidgets</code> is:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>filter_view<span class="op">&lt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>elements_view<span class="op">&lt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>ranges<span class="op">::</span>ref_view<span class="op">&lt;</span>std<span class="op">::</span>unordered_map<span class="op">&lt;</span>Key, Widget<span class="op">&gt;&gt;</span>,</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="dv">1</span><span class="op">&gt;</span>,</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  MyClass<span class="op">::</span>getWidgets<span class="op">()::&lt;</span>lambda<span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">:</span><span class="dv">11</span><span class="op">&amp;)&gt;</span> <span class="op">&gt;</span></span></code></pre></div>
<p>While this type is already difficult to spell once, it is much harder
and more brittle to maintain it as the implementation or the business
logic evolves. These challenges for templated interfaces are hardly
unique to ranges: the numerous string types in the language and lambdas
are some common examples that lead to similar challenges.</p>
<p>Type-erasure is a very popular technique to hide the concrete type of
an object behind a common interface, allowing polymorphic use of objects
of any type that model a given concept. In fact, it is a technique
commonly employed by the standard. <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>
<code class="sourceCode cpp">std<span class="op">::</span>function</code> and
<code class="sourceCode cpp">std<span class="op">::</span>function_ref</code>,
and <code class="sourceCode cpp">std<span class="op">::</span>any</code>
are the type-erased facilities for the examples above.</p>
<p><code class="sourceCode cpp">std<span class="op">::</span>span<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
is another type-erasure utility recently added to the standard; and is
closely related to ranges in fact, by allowing type-erased
<em>reference</em> of any underlying <em>contiguous</em> range of
objects.</p>
<p>In this paper, we propose to extend the standard library with <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>any_view</code>,
which provides a convenient and generalized type-erasure facility to
hold any object of any type that satisfies the
<code class="sourceCode cpp">ranges<span class="op">::</span>view</code>
concept itself. <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>any_view</code>
also allows further refinement via customizable constraints on its
traversal categories and other range characteristics.</p>
<h1 data-number="4" id="design-space-and-prior-art"><span class="header-section-number">4</span> Design Space and Prior Art<a href="#design-space-and-prior-art" class="self-link"></a></h1>
<p>Designing a type like <code class="sourceCode cpp">any_view</code>
raises a lot of questions.</p>
<p>Let’s take <code class="sourceCode cpp">std<span class="op">::</span>function</code> as
an example. At first, its interface seems extremely simple: it provides
<code class="sourceCode cpp"><span class="kw">operator</span><span class="op">()</span></code>
and users only need to configure the return type and argument types of
the function. In reality, <code class="sourceCode cpp">std<span class="op">::</span>function</code>
makes many other decisions for the user:</p>
<ul>
<li>Are <code class="sourceCode cpp">std<span class="op">::</span>function</code> and
the callable it contains
<code class="sourceCode cpp">copyable</code>?</li>
<li>Does <code class="sourceCode cpp">std<span class="op">::</span>function</code> own
the callable it contains?</li>
<li>Does <code class="sourceCode cpp">std<span class="op">::</span>function</code>
propagate const-ness?</li>
</ul>
<p>After answering all these questions we ended up with several
types:</p>
<ul>
<li><code class="sourceCode cpp">function</code></li>
<li><code class="sourceCode cpp">move_only_function</code></li>
<li><code class="sourceCode cpp">function_ref</code></li>
<li><code class="sourceCode cpp">copyable_function</code></li>
</ul>
<p>The design space of <code class="sourceCode cpp">any_view</code> is a
lot more complex than that:</p>
<ul>
<li>Is it an <code class="sourceCode cpp">input_range</code>,
<code class="sourceCode cpp">forward_range</code>,
<code class="sourceCode cpp">bidirectional_range</code>,
<code class="sourceCode cpp">random_access_range</code>, or a
<code class="sourceCode cpp">contiguous_range</code> ?</li>
<li>Is the range <code class="sourceCode cpp">copyable</code> ?</li>
<li>Is it a <code class="sourceCode cpp">sized_range</code> ?</li>
<li>Is it a <code class="sourceCode cpp">borrowed_range</code> ?</li>
<li>Is it a <code class="sourceCode cpp">common_range</code> ?</li>
<li>What is the <code class="sourceCode cpp">range_reference_t</code>
?</li>
<li>What is the <code class="sourceCode cpp">range_value_t</code> ?</li>
<li>What is the
<code class="sourceCode cpp">range_rvalue_reference_t</code> ?</li>
<li>What is the <code class="sourceCode cpp">range_difference_t</code>
?</li>
<li>Is the <code class="sourceCode cpp">range</code>
const-iterable?</li>
<li>Is the iterator <code class="sourceCode cpp">copyable</code> for
<code class="sourceCode cpp">input_iterator</code>?</li>
<li>Is the iterator equality comparable for
<code class="sourceCode cpp">input_iterator</code>?</li>
<li>Do the iterator and sentinel types satisfy <code class="sourceCode cpp">sized_sentinel_for<span class="op">&lt;</span>S, I<span class="op">&gt;</span></code>?</li>
</ul>
<p>We can easily get a combinatorial explosion of types if we follow the
same approach we did for <code class="sourceCode cpp">std<span class="op">::</span>function</code>.
Fortunately, there is prior art to help us guide the design.</p>
<h2 data-number="4.1" id="boost.range-boostrangesany_range"><span class="header-section-number">4.1</span> Boost.Range <code class="sourceCode cpp">boost<span class="op">::</span>ranges<span class="op">::</span>any_range</code><a href="#boost.range-boostrangesany_range" class="self-link"></a></h2>
<p>The type declaration is:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> Value</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  , <span class="kw">class</span> Traversal</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  , <span class="kw">class</span> Reference</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  , <span class="kw">class</span> Difference</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  , <span class="kw">class</span> Buffer <span class="op">=</span> any_iterator_default_buffer</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_range;</span></code></pre></div>
<p>Users will need to provide
<code class="sourceCode cpp">range_reference_t</code>,
<code class="sourceCode cpp">range_value_t</code> and
<code class="sourceCode cpp">range_difference_t</code>.
<code class="sourceCode cpp">Traversal</code> is equivalent to
<code class="sourceCode cpp">iterator_concept</code>, which decides the
traversal category of the range. Users don’t need to specify
<code class="sourceCode cpp">copyable</code>,
<code class="sourceCode cpp">borrowed_range</code> and
<code class="sourceCode cpp">common_range</code>, because all
Boost.Range ranges are <code class="sourceCode cpp">copyable</code>,
<code class="sourceCode cpp">borrowed_range</code> and
<code class="sourceCode cpp">common_range</code>.
<code class="sourceCode cpp">sized_range</code> and
<code class="sourceCode cpp">range_rvalue_reference_t</code> are not
considered in the design.</p>
<h2 data-number="4.2" id="range-v3-rangesviewsany_view"><span class="header-section-number">4.2</span> range-v3 <code class="sourceCode cpp">ranges<span class="op">::</span>views<span class="op">::</span>any_view</code><a href="#range-v3-rangesviewsany_view" class="self-link"></a></h2>
<p>The type declaration is:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> category</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    none <span class="op">=</span> <span class="dv">0</span>,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    input <span class="op">=</span> <span class="dv">1</span>,</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    forward <span class="op">=</span> <span class="dv">3</span>,</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    bidirectional <span class="op">=</span> <span class="dv">7</span>,</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    random_access <span class="op">=</span> <span class="dv">15</span>,</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    mask <span class="op">=</span> random_access,</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    sized <span class="op">=</span> <span class="dv">16</span>,</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> Ref, category Cat <span class="op">=</span> category<span class="op">::</span>input<span class="op">&gt;</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> any_view;</span></code></pre></div>
<p>Here <code class="sourceCode cpp">Cat</code> handles both the
traversal category and <code class="sourceCode cpp">sized_range</code>.
<code class="sourceCode cpp">Ref</code> is the
<code class="sourceCode cpp">range_reference_t</code>. It does not allow
users to configure the
<code class="sourceCode cpp">range_value_t</code>,
<code class="sourceCode cpp">range_difference_t</code>,
<code class="sourceCode cpp">borrowed_range</code> and
<code class="sourceCode cpp">common_range</code>.
<code class="sourceCode cpp">copyable</code> is mandatory in
range-v3.</p>
<h1 data-number="5" id="proposed-design"><span class="header-section-number">5</span> Proposed Design<a href="#proposed-design" class="self-link"></a></h1>
<p>This paper proposes the following interface:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">enum</span> <span class="kw">class</span> any_view_options</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    input <span class="op">=</span> <span class="dv">1</span>,</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    forward <span class="op">=</span> <span class="dv">3</span>,</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    bidirectional <span class="op">=</span> <span class="dv">7</span>,</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    random_access <span class="op">=</span> <span class="dv">15</span>,</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    contiguous <span class="op">=</span> <span class="dv">31</span>,</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    sized <span class="op">=</span> <span class="dv">32</span>,</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>    borrowed <span class="op">=</span> <span class="dv">64</span>,</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    move_only <span class="op">=</span> <span class="dv">128</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Element,</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>          any_view_options Opts <span class="op">=</span> any_view_options<span class="op">::</span>input,</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Ref <span class="op">=</span>  Element<span class="op">&amp;</span>,</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Value <span class="op">=</span> remove_cvref_t<span class="op">&lt;</span>Element<span class="op">&gt;</span>,</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> RValueRef <span class="op">=</span> add_rvalue_reference_t<span class="op">&lt;</span>remove_reference_t<span class="op">&lt;</span>Ref<span class="op">&gt;&gt;</span>,</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Diff <span class="op">=</span> <span class="dt">ptrdiff_t</span><span class="op">&gt;</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_view <span class="op">{</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> iterator; <span class="co">// exposition-only</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> sentinel; <span class="co">// exposition-only</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> View<span class="op">&gt;</span></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(!</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>View, any_view<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> std<span class="op">::</span>ranges<span class="op">::</span>view<span class="op">&lt;</span>View<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a>             view_options_constraint<span class="op">&lt;</span>View<span class="op">&gt;())</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a>  any_view<span class="op">(</span>View view<span class="op">)</span>;</span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a>  any_view<span class="op">(</span><span class="kw">const</span> any_view <span class="op">&amp;)</span> <span class="kw">requires</span> <span class="op">(!(</span>Opts <span class="op">&amp;</span> any_view_options<span class="op">::</span>move_only<span class="op">))</span>;</span>
<span id="cb6-29"><a href="#cb6-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a>  any_view<span class="op">(</span>any_view <span class="op">&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb6-31"><a href="#cb6-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a>  any_view <span class="op">&amp;</span><span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> any_view <span class="op">&amp;)</span> <span class="kw">requires</span> <span class="op">(!(</span>Opts <span class="op">&amp;</span> any_view_options<span class="op">::</span>move_only<span class="op">))</span>;</span>
<span id="cb6-33"><a href="#cb6-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a>  any_view <span class="op">&amp;</span><span class="kw">operator</span><span class="op">=(</span>any_view <span class="op">&amp;&amp;)</span>;</span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a>  iterator begin<span class="op">()</span>;</span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a>  sentinel end<span class="op">()</span>;</span>
<span id="cb6-38"><a href="#cb6-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a>  <span class="dt">size_t</span> size<span class="op">()</span> <span class="kw">const</span> <span class="kw">requires</span><span class="op">(</span>Opts <span class="op">&amp;</span> any_view_options<span class="op">::</span>sized<span class="op">)</span>;</span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Element, any_view_options Opts, <span class="kw">class</span> Ref, <span class="kw">class</span> Value, <span class="kw">class</span> RValueRef,</span>
<span id="cb6-43"><a href="#cb6-43" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Diff<span class="op">&gt;</span></span>
<span id="cb6-44"><a href="#cb6-44" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="dt">bool</span></span>
<span id="cb6-45"><a href="#cb6-45" aria-hidden="true" tabindex="-1"></a>    enable_borrowed_range<span class="op">&lt;</span>any_view<span class="op">&lt;</span>Value, Opts, Ref, RValueRef, Diff<span class="op">&gt;&gt;</span> <span class="op">=</span></span>
<span id="cb6-46"><a href="#cb6-46" aria-hidden="true" tabindex="-1"></a>        Opts <span class="op">&amp;</span> any_view_options<span class="op">::</span>borrowed;</span></code></pre></div>
<p>The intent is that users can select various desired properties of the
<code class="sourceCode cpp">any_view</code> by <code class="sourceCode cpp">bitwise<span class="op">-</span><span class="kw">or</span></code>ing
them. For example:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>Widget, </span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>                                    std<span class="op">::</span>ranges<span class="op">::</span>any_view_options<span class="op">::</span>bidirectional <span class="op">|</span> </span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>                                    std<span class="op">::</span>ranges<span class="op">::</span>any_view_options<span class="op">::</span>sized<span class="op">&gt;</span>;</span></code></pre></div>
<h1 data-number="6" id="alternative-design-for-template-parameters"><span class="header-section-number">6</span> Alternative Design for Template
Parameters<a href="#alternative-design-for-template-parameters" class="self-link"></a></h1>
<p>In Wrocław meeting, one important point was made: The majority of the
use case of <code class="sourceCode cpp">any_view</code> is to use it as
a function parameter in the API boundary.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Bar algo<span class="op">(</span>any_view<span class="op">&lt;</span>Foo<span class="op">&gt;)</span>;</span></code></pre></div>
<p>And in most of cases, the implementation of
<code class="sourceCode cpp">algo</code> only iterate over the range
once. The design should make it easy to specify an
“<code class="sourceCode cpp">input_range</code> only”
<code class="sourceCode cpp">view</code>, and sometimes “read-only”
access to the elements (a
<code class="sourceCode cpp"><span class="kw">const</span></code>
reference element type). That is,</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>any_view<span class="op">&lt;</span>Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is Foo&amp;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>any_view<span class="op">&lt;</span><span class="kw">const</span> Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is const Foo&amp;</span></span></code></pre></div>
<p>With the proposed design, the above two use cases would work. Even
though there are lots of template parameters, we do not expect users to
specify them often because the default would work for majority of the
use cases.</p>
<h2 data-number="6.1" id="alternative-design-1-variadic-named-template-parameters"><span class="header-section-number">6.1</span> Alternative Design 1: Variadic
Named Template Parameters<a href="#alternative-design-1-variadic-named-template-parameters" class="self-link"></a></h2>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> any_view_options <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> iterator_concept;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> reference_type;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> value_type;</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> difference_type;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span><span class="op">&gt;</span> <span class="kw">struct</span> rvalue_reference_type;</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span> <span class="kw">struct</span> sized;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span> <span class="kw">struct</span> move_only;</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span> <span class="kw">struct</span> borrowed;</span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// any_view_options</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-14"><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Element, <span class="kw">class</span><span class="op">...</span> Options<span class="op">&gt;</span></span>
<span id="cb10-15"><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_view;</span></code></pre></div>
<p>With this design, the two main use cases would still work</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView1 <span class="op">=</span> any_view<span class="op">&lt;</span>Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is Foo&amp;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView2 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="kw">const</span> Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is const Foo&amp;</span></span></code></pre></div>
<p>If the default options do not work, users can specify the options in
this way:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>ranges<span class="op">::</span>any_view_options;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView3 <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>Foo, </span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>                                      iterator_concept<span class="op">&lt;</span>std<span class="op">::</span>contiguous_iterator_tag<span class="op">&gt;</span>,</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>                                      reference_type<span class="op">&lt;</span>Foo<span class="op">&gt;</span>,</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>                                      sized<span class="op">&lt;</span><span class="kw">true</span><span class="op">&gt;</span>,</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>                                      borrowed<span class="op">&lt;</span><span class="kw">true</span><span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>The benefits of this approach are</p>
<ul>
<li>Each parameter is named</li>
<li>Users do not need to specify the template parameters in a specific
order</li>
<li>Users can skip few template parameters if they need to customize the
“last” template option</li>
</ul>
<p>An implementation of this approach would look like this: <a href="https://godbolt.org/z/qdnoE7Mb9">link</a></p>
<p>However, we believe that this overcomplicates the design.</p>
<h2 data-number="6.2" id="alternative-design-2-single-template-parameter-rangetraits"><span class="header-section-number">6.2</span> Alternative Design 2: Single
Template Parameter: RangeTraits<a href="#alternative-design-2-single-template-parameter-rangetraits" class="self-link"></a></h2>
<p>In Wrocław meeting, one feedback we had was to explore the options to
have “single expansion point”, i.e not to have too many template
parameters</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> default_range_traits <span class="op">{}</span>;</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Element, <span class="kw">class</span> RangeTraits <span class="op">=</span> default_range_traits<span class="op">&gt;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_view;</span></code></pre></div>
<p>In the <code class="sourceCode cpp">RangeTraits</code>, the user can
define aliases to customize
<code class="sourceCode cpp">iterator_concept</code>,
<code class="sourceCode cpp">reference_type</code> etc, and define <code class="sourceCode cpp"><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span></code>
variables to customize <code class="sourceCode cpp">sized</code>,
<code class="sourceCode cpp">move_only</code> etc. If an alias or <code class="sourceCode cpp"><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span></code>
variable is missing, the default type or value will be used.</p>
<p>With this design, the two main use cases would still work</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView1 <span class="op">=</span> any_view<span class="op">&lt;</span>Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is Foo&amp;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView2 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="kw">const</span> Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is const Foo&amp;</span></span></code></pre></div>
<p>If the default options do not work, users can specify the options in
this way:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> MyTraits <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> iterator_concept <span class="op">=</span> std<span class="op">::</span>contiguous_iterator_tag;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> sized <span class="op">=</span> <span class="kw">true</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> move_only <span class="op">=</span> <span class="kw">true</span>;</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView3 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="dt">int</span>, MyTraits<span class="op">&gt;</span>;</span></code></pre></div>
<p>The benefits of this approach are</p>
<ul>
<li>Each option is named</li>
<li>Users do not need to specify the template parameters in a specific
order</li>
<li>Users can skip any options if they can use the default values</li>
</ul>
<p>An implementation of this approach would look like this: <a href="https://godbolt.org/z/596avP8T5">link</a></p>
<p>However, every time an user needs to customize anything, they need to
define a
<code class="sourceCode cpp"><span class="kw">struct</span></code>,
which is verbose and inconvenient.</p>
<h3 data-number="6.2.1" id="optional-add-on-to-rangetraits"><span class="header-section-number">6.2.1</span> Optional add-on to
<code class="sourceCode cpp">RangeTraits</code><a href="#optional-add-on-to-rangetraits" class="self-link"></a></h3>
<p>If we decided to go with this alternative, we could have a utility
that deduces the traits from another range.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Range<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> range_traits <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> iterator_concept <span class="op">=</span> <span class="co">/* see-below */</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> reference_type <span class="op">=</span> range_reference_t<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> value_type <span class="op">=</span> range_value_t<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> rvalue_reference_type <span class="op">=</span> range_rvalue_reference_t<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> difference_type <span class="op">=</span> range_difference_t<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> sized <span class="op">=</span> sized_range<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> move_only <span class="op">=</span> <span class="op">!</span>copyable<span class="op">&lt;</span>decay_t<span class="op">&lt;</span>Range<span class="op">&gt;&gt;</span>;</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> borrowed <span class="op">=</span> borrowed_range<span class="op">&lt;</span>Range<span class="op">&gt;</span>;</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="co">// MyView4 is a contiguous, sized, copyable, non-borrowed int&amp; range </span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView4 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="dt">int</span>, range_traits<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;&gt;</span>;</span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a><span class="co">// MyView5 is a contiguous, sized, copyable, non-borrowed const int&amp; range </span></span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView5 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">int</span>, range_traits<span class="op">&lt;</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;&gt;&gt;</span>;</span></code></pre></div>
<p>An implementation of this approach would look like this: <a href="https://godbolt.org/z/co1Kdsra3">link</a></p>
<h2 data-number="6.3" id="alternative-design-3-barrys-named-template-argument-approach"><span class="header-section-number">6.3</span> Alternative Design 3: Barry’s
Named Template Argument Approach<a href="#alternative-design-3-barrys-named-template-argument-approach" class="self-link"></a></h2>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> type_t <span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> type <span class="op">=</span> T;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> type_t<span class="op">&lt;</span>T<span class="op">&gt;</span> type<span class="op">{}</span>;</span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Ref,</span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> IterConcept <span class="op">=</span> input_iterator_tag,</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Value <span class="op">=</span> decay_t<span class="op">&lt;</span>Ref<span class="op">&gt;</span>,</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> RValueRef <span class="op">=</span> remove_reference_t<span class="op">&lt;</span>Ref<span class="op">&gt;&amp;&amp;</span>,</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Difference <span class="op">=</span> <span class="dt">ptrdiff_t</span><span class="op">&gt;</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> any_view_options <span class="op">{</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>    type_t<span class="op">&lt;</span>Ref<span class="op">&gt;</span> reference_type;</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>    type_t<span class="op">&lt;</span>IterConcept<span class="op">&gt;</span> iterator_concept <span class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> sized <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> move_only <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>    <span class="dt">bool</span> borrowed <span class="op">=</span> <span class="kw">false</span>;</span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>    type_t<span class="op">&lt;</span>Value<span class="op">&gt;</span> value_type;</span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>    type_t<span class="op">&lt;</span>RValueRef<span class="op">&gt;</span> rvalue_reference_type;</span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a>    type_t<span class="op">&lt;</span>Difference<span class="op">&gt;</span> difference_type;</span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Element, any_view_options options <span class="op">=</span> <span class="op">{.</span>reference_type <span class="op">=</span> type<span class="op">&lt;</span>Element<span class="op">&amp;&gt;}&gt;</span></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_view;</span></code></pre></div>
<p>This is inspired by Barry’s <a href="https://brevzin.github.io/c++/2019/12/02/named-arguments/">blog
post</a>. Thanks to designated initializers and generated CTAD, the user
code is extremely readable</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView1 <span class="op">=</span> any_view<span class="op">&lt;</span>Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is Foo&amp;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView2 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="kw">const</span> Foo<span class="op">&gt;</span>; <span class="co">// should be an input_range where the range_reference_t is const Foo&amp;</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView3 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="dt">int</span>, <span class="op">{.</span>reference_type <span class="op">=</span> type<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span>,</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>iterator_concept <span class="op">=</span> type<span class="op">&lt;</span>std<span class="op">::</span>contiguous_iterator_tag<span class="op">&gt;</span>,</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>value_type <span class="op">=</span> type<span class="op">&lt;</span><span class="dt">long</span><span class="op">&gt;}&gt;</span>;</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> MyView4 <span class="op">=</span> any_view<span class="op">&lt;</span><span class="dt">int</span>, <span class="op">{.</span>reference_type <span class="op">=</span> type<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span>,</span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>iterator_concept <span class="op">=</span> type<span class="op">&lt;</span>std<span class="op">::</span>contiguous_iterator_tag<span class="op">&gt;</span>,</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>sized <span class="op">=</span> <span class="kw">true</span>,</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>borrowed <span class="op">=</span> <span class="kw">true</span>,</span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>                               <span class="op">.</span>value_type <span class="op">=</span> type<span class="op">&lt;</span><span class="dt">long</span><span class="op">&gt;}&gt;</span>;                        </span></code></pre></div>
<p>Each option is named and user can skip parameters if they want to use
the default. However, the user has to follow the same order of the
options that are defined in
<code class="sourceCode cpp">any_view_options</code>.</p>
<p>An implementation of this approach would look like this: <a href="https://godbolt.org/z/4dGYneWxx">link</a></p>
<h1 data-number="7" id="other-design-considerations"><span class="header-section-number">7</span> Other Design Considerations<a href="#other-design-considerations" class="self-link"></a></h1>
<h2 data-number="7.1" id="why-dont-follow-range-v3s-design-where-first-template-parameter-is-range_reference_t"><span class="header-section-number">7.1</span> Why don’t follow range-v3’s
design where first template parameter is
<code class="sourceCode cpp">range_reference_t</code>?<a href="#why-dont-follow-range-v3s-design-where-first-template-parameter-is-range_reference_t" class="self-link"></a></h2>
<p>If the first template parameter is
<code class="sourceCode cpp">Ref</code>, we have:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Ref,</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>          any_view_options Opts <span class="op">=</span> any_view_options<span class="op">::</span>input,</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Value <span class="op">=</span> remove_cvref_t<span class="op">&lt;</span>Ref<span class="op">&gt;&gt;</span></span></code></pre></div>
<p>For a range with a reference to
<code class="sourceCode cpp">T</code>, one would write</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>any_view<span class="op">&lt;</span>T<span class="op">&amp;&gt;</span></span></code></pre></div>
<p>And for a
<code class="sourceCode cpp"><span class="kw">const</span></code>
reference to <code class="sourceCode cpp">T</code>, one would write</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>any_view<span class="op">&lt;</span><span class="kw">const</span> T<span class="op">&amp;&gt;</span></span></code></pre></div>
<p>However, it is possible that the user uses <code class="sourceCode cpp">any_view<span class="op">&lt;</span>string<span class="op">&gt;</span></code>
without realizing that they specified the reference type and they now
make a copy of the <code class="sourceCode cpp">string</code> every time
when the iterator is dereferenced.</p>
<h2 data-number="7.2" id="name-of-the-any_view_options"><span class="header-section-number">7.2</span> Name of the
<code class="sourceCode cpp">any_view_options</code><a href="#name-of-the-any_view_options" class="self-link"></a></h2>
<p><code class="sourceCode cpp">range<span class="op">-</span>v3</code>
uses the name <code class="sourceCode cpp">category</code> for the
category enumeration type. However, the authors believe that the name
<code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>category</code>
is too general and it should be reserved for more general purpose
utility in ranges library. Therefore, the authors recommend a more
specific name: <code class="sourceCode cpp">any_view_options</code>.</p>
<h2 data-number="7.3" id="constexpr-support"><span class="header-section-number">7.3</span>
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
Support<a href="#constexpr-support" class="self-link"></a></h2>
<p>We do not require
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> in
order to allow efficient implementations using e.g. SBO. There is no
way, with the current working draft, to construct an object of different
type on a <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">[</span>N<span class="op">]</span></code>
or <code class="sourceCode cpp">std<span class="op">::</span>byte<span class="op">[</span>N<span class="op">]</span></code>
buffer in
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
context.</p>
<h2 data-number="7.4" id="move-only-view-support"><span class="header-section-number">7.4</span> Move-only
<code class="sourceCode cpp">view</code> Support<a href="#move-only-view-support" class="self-link"></a></h2>
<p>Move-only <code class="sourceCode cpp">view</code> is worth
supporting as we generally support them in
<code class="sourceCode cpp">ranges</code>. We propose to have a
configuration template parameter <code class="sourceCode cpp">any_view_options<span class="op">::</span>move_only</code>
to make the <code class="sourceCode cpp">any_view</code> conditionally
move-only. This removes the need to have another type
<code class="sourceCode cpp">move_only_any_view</code> as we did for
<code class="sourceCode cpp">move_only_function</code>.</p>
<p>We also propose that by default,
<code class="sourceCode cpp">any_view</code> is copyable and to make it
move-only, the user needs to explicitly provide this template parameter
<code class="sourceCode cpp">any_view_options<span class="op">::</span>move_only</code>.</p>
<h2 data-number="7.5" id="move-only-iterator-support"><span class="header-section-number">7.5</span> Move-only
<code class="sourceCode cpp">iterator</code> Support<a href="#move-only-iterator-support" class="self-link"></a></h2>
<p>In this proposal, <code class="sourceCode cpp">any_view<span class="op">::</span>iterator</code>
is an exposition-only type. It is not worth making this
<code class="sourceCode cpp">iterator</code> configurable. If the
<code class="sourceCode cpp">iterator</code> is only
<code class="sourceCode cpp">input_iterator</code>, we can also make it
a move-only iterator. There is no need to make it copyable. Existing
algorithms that take “input only” iterators already know that they
cannot copy them.</p>
<h2 data-number="7.6" id="is-any_view_optionscontiguous-needed"><span class="header-section-number">7.6</span> Is <code class="sourceCode cpp">any_view_options<span class="op">::</span>contiguous</code>
Needed ?<a href="#is-any_view_optionscontiguous-needed" class="self-link"></a></h2>
<p><code class="sourceCode cpp">contiguous_range</code> is still useful
to support even though we have already
<code class="sourceCode cpp">std<span class="op">::</span>span</code>.
But <code class="sourceCode cpp">span</code> is non-owning and
<code class="sourceCode cpp">any_view</code> owns the underlying
<code class="sourceCode cpp">view</code>.</p>
<h2 data-number="7.7" id="is-any_view-const-iterable"><span class="header-section-number">7.7</span> Is
<code class="sourceCode cpp">any_view</code> const-iterable?<a href="#is-any_view-const-iterable" class="self-link"></a></h2>
<p>We cannot make <code class="sourceCode cpp">any_view</code>
unconditionally const-iterable. If we did,
<code class="sourceCode cpp">views</code> with cache-on-begin, like
<code class="sourceCode cpp">filter_view</code> and
<code class="sourceCode cpp">drop_while_view</code> could no longer be
put into an <code class="sourceCode cpp">any_view</code>.</p>
<p>One option would be to make
<code class="sourceCode cpp">any_view</code> conditionally
const-iterable, via a configuration template parameter. However, this
would make the whole interface much more complicated, as each
configuration template parameter would need to be duplicated. Indeed,
associated types like <code class="sourceCode cpp">Ref</code> and
<code class="sourceCode cpp">RValueRef</code> can be different between
<code class="sourceCode cpp"><span class="kw">const</span></code> and
non-<code class="sourceCode cpp"><span class="kw">const</span></code>
iterators.</p>
<p>For simplicity, the authors propose to make
<code class="sourceCode cpp">any_view</code> unconditionally
non-const-iterable.</p>
<h2 data-number="7.8" id="common_range-support"><span class="header-section-number">7.8</span>
<code class="sourceCode cpp">common_range</code> support<a href="#common_range-support" class="self-link"></a></h2>
<p>Unconditionally making <code class="sourceCode cpp">any_view</code> a
<code class="sourceCode cpp">common_range</code> is not an option. This
would exclude most of the Standard Library
<code class="sourceCode cpp">view</code>s. Adding a configuration
template parameter to make <code class="sourceCode cpp">any_view</code>
conditionally <code class="sourceCode cpp">common_range</code> is
overkill. After all, if users need
<code class="sourceCode cpp">common_range</code>, they can use <code class="sourceCode cpp">my_any_view <span class="op">|</span> views<span class="op">::</span>common</code>.
Furthermore, supporting this turns out to add substantial complexity in
the implementation. The authors believe that adding
<code class="sourceCode cpp">common_range</code> support is not worth
the added complexity.</p>
<h2 data-number="7.9" id="borrowed_range-support"><span class="header-section-number">7.9</span>
<code class="sourceCode cpp">borrowed_range</code> support<a href="#borrowed_range-support" class="self-link"></a></h2>
<p>Having support for <code class="sourceCode cpp">borrowed_range</code>
is simple enough:</p>
<ul>
<li><ol type="1">
<li>Add a template configuration parameter</li>
</ol></li>
<li><ol start="2" type="1">
<li>Specialise the
<code class="sourceCode cpp">enable_borrowed_range</code> if the
template parameter is set to
<code class="sourceCode cpp"><span class="kw">true</span></code></li>
</ol></li>
</ul>
<p>Therefore, we recommend conditional support for
<code class="sourceCode cpp">borrowed_range</code>. However, since
<code class="sourceCode cpp">borrowed_range</code> is not a very useful
concept in general, this design point is open for discussion.</p>
<h2 data-number="7.10" id="valueless-state-of-any_view"><span class="header-section-number">7.10</span> Valueless state of
<code class="sourceCode cpp">any_view</code><a href="#valueless-state-of-any_view" class="self-link"></a></h2>
<p>We propose providing the strong exception safety guarantee in the
following operations: swap, copy-assignment, move-assignment and
move-construction. This means that if the operation fails, the two
<code class="sourceCode cpp">any_view</code> objects will be in their
original states. If the underlying view’s move constructor (or
move-assignment operator) is not
<code class="sourceCode cpp"><span class="kw">noexcept</span></code>,
the only way to achieve the strong exception safety guarantee is to
avoid calling these operations altogether, which requires
<code class="sourceCode cpp">any_view</code> to hold its underlying
object on the heap so it can implement these operations by swapping
pointers. This means that any implementation of
<code class="sourceCode cpp">any_view</code> will have an empty state,
and a “moved-from” <code class="sourceCode cpp">any_view</code> will be
in that state.</p>
<h2 data-number="7.11" id="abi-stability"><span class="header-section-number">7.11</span> ABI Stability<a href="#abi-stability" class="self-link"></a></h2>
<p>As a type intended to exist at ABI boundaries, ensuring the ABI
stability of <code class="sourceCode cpp">any_view</code> is extremely
important. However, since almost any change to the API of
<code class="sourceCode cpp">any_view</code> will require a modification
to the vtable, this makes <code class="sourceCode cpp">any_view</code>
somewhat fragile to incremental evolution. This drawback is shared by
all C++ types that live at ABI boundaries, and while we don’t think this
impacts the livelihood of <code class="sourceCode cpp">any_view</code>,
this evolutionary challenge should be kept in mind by WG21.</p>
<h2 data-number="7.12" id="performance"><span class="header-section-number">7.12</span> Performance<a href="#performance" class="self-link"></a></h2>
<p>One of the major concerns of using type erasure is the performance
cost of indirect function calls and their impact on the ability for the
compiler to perform optimizations. With
<code class="sourceCode cpp">any_view</code>, every iteration will have
three indirect function calls:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="op">++</span>it;</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>it <span class="op">!=</span> last;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span>it;</span></code></pre></div>
<p>While it may at first seem prohibitive, it is useful to remember the
context in which <code class="sourceCode cpp">any_view</code> is used
and what the alternatives to it are.</p>
<p>The following benchmarks were compiled with clang 20 with libc++,
with -O3, run on APPLE M4 MAX CPU with 16 cores. We have done the same
benchmarks on a 8 core Intel CPU and they have very similar results.</p>
<h3 data-number="7.12.1" id="a-naive-micro-benchmark-iteration-over-vector-vs-any_view"><span class="header-section-number">7.12.1</span> A naive micro benchmark:
iteration over <code class="sourceCode cpp">vector</code> vs
<code class="sourceCode cpp">any_view</code><a href="#a-naive-micro-benchmark-iteration-over-vector-vs-any_view" class="self-link"></a></h3>
<p>Naively, one would be tempted to benchmark the cost of iterating over
a
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
and to compare it with the cost of iterating over
<code class="sourceCode cpp">any_view</code>. For example, the following
code:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector v <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, state<span class="op">.</span>range<span class="op">(</span><span class="dv">0</span><span class="op">))</span> <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>to<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&gt;()</span>;</span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> _ <span class="op">:</span> state<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> i <span class="op">:</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>      benchmark<span class="op">::</span>DoNotOptimize<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>vs</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector v <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, state<span class="op">.</span>range<span class="op">(</span><span class="dv">0</span><span class="op">))</span> <span class="op">|</span> std<span class="op">::</span>ranges<span class="op">::</span>to<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&gt;()</span>;</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span> av<span class="op">(</span>std<span class="op">::</span>views<span class="op">::</span>all<span class="op">(</span>v<span class="op">))</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> _ <span class="op">:</span> state<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> i <span class="op">:</span> av<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>      benchmark<span class="op">::</span>DoNotOptimize<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                           Time      Time vector   Time any_view</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">-----------------------------------------------------------------------------------------</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/1024                  +7.3364              237            1975</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/2048                  +7.7186              464            4042</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/4096                  +7.7098              920            8011</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/8192                  +7.6034             1835           15790</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/16384                 +7.7470             3654           31966</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/32768                 +8.1498             7300           66796</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/65536                 +8.0808            14602          132599</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/131072                +8.0281            29189          263523</span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/262144                +7.4773            58497          495899</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                  +8.6630                0               0</span></code></pre></div>
<p>We can see that <code class="sourceCode cpp">any_view</code> is 8.6
times slower on iteration than
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>.
However, this benchmark is not a realistic use case. No one would create
a <code class="sourceCode cpp">vector</code>, immediately create a type
erased wrapper <code class="sourceCode cpp">any_view</code> that wraps
it and then iterate through it. Similarly, no one would create a lambda,
immediately create a <code class="sourceCode cpp">std<span class="op">::</span>function</code> and
then call it.</p>
<h3 data-number="7.12.2" id="a-slightly-more-realistic-benchmark-a-view-pipeline-vs-any_view"><span class="header-section-number">7.12.2</span> A slightly more realistic
benchmark: A view pipeline vs
<code class="sourceCode cpp">any_view</code><a href="#a-slightly-more-realistic-benchmark-a-view-pipeline-vs-any_view" class="self-link"></a></h3>
<p>Since <code class="sourceCode cpp">any_view</code> is intended to be
used at an ABI boundary, a more realistic benchmark would separate the
creation of the view in a different TU. Furthermore, most uses of
<code class="sourceCode cpp">any_view</code> are expected to be with
non-trivial view pipelines, not with e.g. a raw
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>.
As the pipeline increases in complexity, the relative cost of using
<code class="sourceCode cpp">any_view</code> becomes smaller and
smaller.</p>
<p>Let’s consider the following example, where we create a moderately
complex pipeline and pass it across an ABI boundary either with a
<code class="sourceCode cpp">any_view</code> or with the pipeline’s
actual type:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co">// header file</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Widget <span class="op">{</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string name;</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> size;</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UI <span class="op">{</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>Widget<span class="op">&gt;</span> widgets_;</span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>transform_view<span class="op">&lt;</span>complicated<span class="op">...&gt;</span> getWidgetNames<span class="op">()</span>;</span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a><span class="co">// cpp file</span></span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>transform_view<span class="op">&lt;</span>complicated<span class="op">...&gt;</span> UI<span class="op">::</span>getWidgetNames<span class="op">()</span> <span class="op">{</span></span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> widgets_ <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>filter<span class="op">([](</span><span class="kw">const</span> Widget<span class="op">&amp;</span> widget<span class="op">)</span> <span class="op">{</span></span>
<span id="cb25-15"><a href="#cb25-15" aria-hidden="true" tabindex="-1"></a>           <span class="cf">return</span> widget<span class="op">.</span>size <span class="op">&gt;</span> <span class="dv">10</span>;</span>
<span id="cb25-16"><a href="#cb25-16" aria-hidden="true" tabindex="-1"></a>         <span class="op">})</span> <span class="op">|</span></span>
<span id="cb25-17"><a href="#cb25-17" aria-hidden="true" tabindex="-1"></a>         std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">(&amp;</span>Widget<span class="op">::</span>name<span class="op">)</span>;</span>
<span id="cb25-18"><a href="#cb25-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>And this is what we are going to measure:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>  lib<span class="op">::</span>UI ui <span class="op">=</span> <span class="op">{...}</span>;</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> _ <span class="op">:</span> state<span class="op">)</span> <span class="op">{</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span><span class="op">&amp;</span> name <span class="op">:</span> ui<span class="op">.</span>getWidgetNames<span class="op">())</span> <span class="op">{</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>      benchmark<span class="op">::</span>DoNotOptimize<span class="op">(</span>name<span class="op">)</span>;</span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>In the <code class="sourceCode cpp">any_view</code> case, we simply
replace <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>transform_view<span class="op">&lt;</span>complicated<span class="op">...&gt;</span></code>
by <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>any_view</code>
and we measure the same thing.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                                 Time    Time complicated      Time any_view</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">-----------------------------------------------------------------------------------------------------</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/1024           +0.8536                1315               2438</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/2048           +0.8162                2713               4928</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/4096           +0.6976                5637               9570</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/8192           +0.7154               11539              19795</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/16384          +0.6611               23475              38994</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/32768          +0.6379               47792              78278</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/65536          +0.6174               96976             156851</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/131072         +0.6087              197407             317560</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/262144         +0.5882              399623             634694</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                        +0.6862                   0                  0</span></code></pre></div>
<p>This benchmark shows that
<code class="sourceCode cpp">any_view</code> is about 68% slower on
iteration, which is much better than the previous naive benchmark.
However, note that this benchmark is still not very realistic. Writing
down the type of the view pipeline causes an implementation detail (how
the pipeline is implemented) to leak into the API and the ABI of this
class, and increases header dependencies, which defeats the purpose of
hiding implementation into a separate translation unit.</p>
<p>As a result, most people would instead copy the results of the
pipeline into a container and return that from <code class="sourceCode cpp">getWidgetNames<span class="op">()</span></code>,
for example as 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>.
This leads us to our last benchmark, which we believe is much more
representative of what people would do in the wild.</p>
<h3 data-number="7.12.3" id="a-realistic-benchmark-a-copy-of-vectorstring-vs-any_view"><span class="header-section-number">7.12.3</span> A realistic benchmark: A
copy of <code class="sourceCode cpp">vector<span class="op">&lt;</span>string<span class="op">&gt;</span></code>
vs <code class="sourceCode cpp">any_view</code><a href="#a-realistic-benchmark-a-copy-of-vectorstring-vs-any_view" class="self-link"></a></h3>
<p>As mentioned above, various concerns that are not related to
performance like readability or API/ABI stability mean that the previous
benchmarks are not really representative of what happens in the real
world. Instead, people in the wild tend to use owning containers like
<code class="sourceCode cpp">std<span class="op">::</span>vector</code>
as a type erasure tool for lack of a better tool. Such code would look
like this:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="co">// header file</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UI <span class="op">{</span></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>Widget<span class="op">&gt;</span> widgets_;</span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> getWidgetNames<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a><span class="co">// cpp file</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> UI<span class="op">::</span>getWidgetNames<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> results;</span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> Widget<span class="op">&amp;</span> widget <span class="op">:</span> widgets_<span class="op">)</span> <span class="op">{</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>widget<span class="op">.</span>size <span class="op">&gt;</span> <span class="dv">10</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a>      results<span class="op">.</span>push_back<span class="op">(</span>widget<span class="op">.</span>name<span class="op">)</span>;</span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> results;</span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                                       Time      Time vector Time any_view</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">---------------------------------------------------------------------------------------------------</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/1024                  <span class="at">-0.7042</span>             8243          2438</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/2048                  <span class="at">-0.7226</span>            17764          4928</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/4096                  <span class="at">-0.7379</span>            36516          9570</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/8192                  <span class="at">-0.7927</span>            95467         19795</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/16384                 <span class="at">-0.7893</span>           185104         38994</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/32768                 <span class="at">-0.7890</span>           371035         78278</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/65536                 <span class="at">-0.8079</span>           816621        156851</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/131072                <span class="at">-0.8121</span>          1690305        317560</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/262144                <span class="at">-0.8228</span>          3581632        634694</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                              <span class="at">-0.7723</span>                0             0</span></code></pre></div>
<p>With this more realistic use case, we can see that
<code class="sourceCode cpp">any_view</code> is 3 times faster. For the
returning <code class="sourceCode cpp">vector</code> case, we have some
variations of the implementations to produce the vector, including
<code class="sourceCode cpp">reserve</code> the maximum possible size,
or use the range pipelines with
<code class="sourceCode cpp">ranges<span class="op">::</span>to</code>.
They all have extremely similar results. In our benchmark, 10% of the
<code class="sourceCode cpp">Widget</code>s were filtered out by the
filter pipeline and the <code class="sourceCode cpp">name</code>
string’s length is randomly 0-30. So some of
<code class="sourceCode cpp">string</code>s are in the SBO and some are
allocated on the heap. We maintain that this code pattern is very common
in the wild: making the code simple and clean at the cost of copying
data, even though most of the callers don’t actually need a copy of the
data at all.</p>
<p>In conclusion, we believe that while it’s easy to craft benchmarks
that make <code class="sourceCode cpp">any_view</code> look bad
performance-wise, in reality this type can often lead to better
performance by sidestepping the need to own the data being iterated
over.</p>
<p>Furthermore, by putting this type in the Standard library, we would
make it possible for implementers to use optimizations like selective
devirtualization of some common operations like
<code class="sourceCode cpp">for_each</code> to achieve large
performance gains in specific cases.</p>
<h3 data-number="7.12.4" id="another-common-use-case-function-arguments-vector-vs-any_view"><span class="header-section-number">7.12.4</span> Another Common Use Case:
Function Arguments <code class="sourceCode cpp">vector</code> vs
<code class="sourceCode cpp">any_view</code><a href="#another-common-use-case-function-arguments-vector-vs-any_view" class="self-link"></a></h3>
<p>Another very common use case is that library authors provide an API
that takes a range of elements. The library authors would like to hide
implementation details in its own library to reduce the header
dependencies and avoid leaking implementation details. Due to the lack
of type erasure utilities, typically the API takes a
<code class="sourceCode cpp">vector</code>, even though the
implementation only needs to iterate once over the elements.</p>
<p>This is the benchmark we are measuring.</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="co">// algo.hpp</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> algo1<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;&amp;</span> strings<span class="op">)</span>;</span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> algo2<span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> strings<span class="op">)</span>;</span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a><span class="co">// algo.cpp</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> algo1<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;&amp;</span> strings<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> result <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb28-8"><a href="#cb28-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> str <span class="op">:</span> strings<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-9"><a href="#cb28-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>str<span class="op">.</span>size<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">6</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a>      result <span class="op">+=</span> str<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> result;</span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb28-15"><a href="#cb28-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-16"><a href="#cb28-16" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> algo2<span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>any_view<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> strings<span class="op">)</span></span>
<span id="cb28-17"><a href="#cb28-17" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb28-18"><a href="#cb28-18" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> result <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb28-19"><a href="#cb28-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> str <span class="op">:</span> strings<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-20"><a href="#cb28-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>str<span class="op">.</span>size<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">6</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-21"><a href="#cb28-21" aria-hidden="true" tabindex="-1"></a>      result <span class="op">+=</span> str<span class="op">.</span>size<span class="op">()</span>;</span>
<span id="cb28-22"><a href="#cb28-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb28-23"><a href="#cb28-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb28-24"><a href="#cb28-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> result;</span>
<span id="cb28-25"><a href="#cb28-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>With the <code class="sourceCode cpp">vector</code> version, the user
needs to create a temporary <code class="sourceCode cpp">vector</code>
if they do not have it at the first place. So in our benchmark, we are
measuring</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> _ <span class="op">:</span> state<span class="op">)</span> <span class="op">{</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> widget_names;</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>  widget_names<span class="op">.</span>reserve<span class="op">(</span>ui<span class="op">.</span>widgets_<span class="op">.</span>size<span class="op">())</span>;</span>
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;</span> widget <span class="op">:</span> ui<span class="op">.</span>widgets_<span class="op">)</span> <span class="op">{</span></span>
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a>    widget_names<span class="op">.</span>push_back<span class="op">(</span>widget<span class="op">.</span>name<span class="op">)</span>;</span>
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> res <span class="op">=</span> lib<span class="op">::</span>algo1<span class="op">(</span>widget_names<span class="op">)</span>;</span>
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a>  benchmark<span class="op">::</span>DoNotOptimize<span class="op">(</span>res<span class="op">)</span>;</span>
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>With the <code class="sourceCode cpp">any_view</code>, we can simply
pass in a <code class="sourceCode cpp">transform_view</code></p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> _ <span class="op">:</span> state<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> res <span class="op">=</span> lib<span class="op">::</span>algo2<span class="op">(</span>ui<span class="op">.</span>widgets_ <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">(&amp;</span>Widget<span class="op">::</span>name<span class="op">))</span>;</span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>  benchmark<span class="op">::</span>DoNotOptimize<span class="op">(</span>res<span class="op">)</span>;</span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>And here is the result:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                                     Time   Time vector Time any_view</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">----------------------------------------------------------------------------------------------</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/1024                  <span class="at">-0.8098</span>          9615          1829</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/2048                  <span class="at">-0.8169</span>         20651          3782</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/4096                  <span class="at">-0.8188</span>         41035          7436</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/8192                  <span class="at">-0.8275</span>         87227         15044</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/16384                 <span class="at">-0.8315</span>        182922         30818</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/32768                 <span class="at">-0.8407</span>        381383         60771</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/65536                 <span class="at">-0.8425</span>        793920        125004</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/131072                <span class="at">-0.8656</span>       1733654        232982</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_algo_vector</span> vs. BM_algo_AnyView]/262144                <span class="at">-0.8640</span>       3592842        488714</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                            <span class="at">-0.8364</span>             0             0</span></code></pre></div>
<p>We can see the <code class="sourceCode cpp">any_view</code> version
is 4 times faster. This is a very common pattern in the real world code.
<code class="sourceCode cpp">vector</code> has been used in API
boundaries as a type-erasure tool.</p>
<h1 data-number="8" id="implementation-experience"><span class="header-section-number">8</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h1>
<p><code class="sourceCode cpp">any_view</code> has been implemented in
<span class="citation" data-cites="rangev3">[<a href="https://github.com/ericniebler/range-v3" role="doc-biblioref">range-v3</a>]</span>, with equivalent semantics as
proposed here. The authors also implemented a version that directly
follows the proposed wording below without any issue <span class="citation" data-cites="ours">[<a href="https://github.com/huixie90/cpp_papers/tree/main/impl/any_view" role="doc-biblioref">ours</a>]</span>.</p>
<style>
.bq{
    display: block;
    margin-block-start: 1em;
    margin-block-end: 1em;
    margin-inline-start: 40px;
    margin-inline-end: 40px;
}
</style>
<h1 data-number="9" id="bibliography"><span class="header-section-number">9</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-ours" class="csl-entry" role="doc-biblioentry">
[ours] Hui Xie, S. Levent Yilmaz, and Dionne Louis. A proof-of-concept
implementation of <code class="sourceCode cpp">any_view</code>. <a href="https://github.com/huixie90/cpp_papers/tree/main/impl/any_view"><div class="csl-block">https://github.com/huixie90/cpp_papers/tree/main/impl/any_view</div></a>
</div>
<div id="ref-rangev3" class="csl-entry" role="doc-biblioentry">
[range-v3] Eric Niebler. range-v3 library. <a href="https://github.com/ericniebler/range-v3"><div class="csl-block">https://github.com/ericniebler/range-v3</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
