<!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-07-06" />
  <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 default">any_view</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3411R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-07-06</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      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>
      S. Levent Yilmaz<br>&lt;<a href="mailto:levent.yilmaz@gmail.com" class="email">levent.yilmaz@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>
    </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="#r0" id="toc-r0"><span class="toc-section-number">1.1</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 default">boost::ranges::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 default">ranges::views::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="#other-design-considerations" id="toc-other-design-considerations"><span class="toc-section-number">6</span> Other Design
Considerations<span></span></a>
<ul>
<li><a href="#should-the-first-argument-be-ref-or-value" id="toc-should-the-first-argument-be-ref-or-value"><span class="toc-section-number">6.1</span> Should the first argument be
<code class="sourceCode default">Ref</code> or
<code class="sourceCode default">Value</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">6.2</span> Name of the
<code class="sourceCode default">any_view_options</code><span></span></a></li>
<li><a href="#constexpr-support" id="toc-constexpr-support"><span class="toc-section-number">6.3</span>
<code class="sourceCode default">constexpr</code>
Support<span></span></a></li>
<li><a href="#move-only-view-support" id="toc-move-only-view-support"><span class="toc-section-number">6.4</span> Move-only
<code class="sourceCode default">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">6.5</span> Move-only
<code class="sourceCode default">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">6.6</span> Is
<code class="sourceCode default">any_view_options::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">6.7</span> Is
<code class="sourceCode default">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">6.8</span>
<code class="sourceCode default">common_range</code>
support<span></span></a></li>
<li><a href="#borrowed_range-support" id="toc-borrowed_range-support"><span class="toc-section-number">6.9</span>
<code class="sourceCode default">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">6.10</span> Valueless state of
<code class="sourceCode default">any_view</code><span></span></a></li>
<li><a href="#abi-stability" id="toc-abi-stability"><span class="toc-section-number">6.11</span> ABI
Stability<span></span></a></li>
<li><a href="#performance" id="toc-performance"><span class="toc-section-number">6.12</span> Performance<span></span></a>
<ul>
<li><a href="#a-naive-micro-benchmark-iteration-over-vector-vs-any_view" id="toc-a-naive-micro-benchmark-iteration-over-vector-vs-any_view"><span class="toc-section-number">6.12.1</span> A naive micro benchmark:
iteration over <code class="sourceCode default">vector</code> vs
<code class="sourceCode default">any_view</code><span></span></a></li>
<li><a href="#a-slightly-more-realistic-benchmark-a-view-pipeline-vs-any_view" id="toc-a-slightly-more-realistic-benchmark-a-view-pipeline-vs-any_view"><span class="toc-section-number">6.12.2</span> A slightly more realistic
benchmark: A view pipeline vs
<code class="sourceCode default">any_view</code><span></span></a></li>
<li><a href="#a-realistic-benchmark-a-copy-of-vectorstring-vs-any_view" id="toc-a-realistic-benchmark-a-copy-of-vectorstring-vs-any_view"><span class="toc-section-number">6.12.3</span> A realistic benchmark: A copy
of <code class="sourceCode default">vector&lt;string&gt;</code> vs
<code class="sourceCode default">any_view</code><span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">7</span> Implementation
Experience<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">8</span> Wording<span></span></a>
<ul>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">8.1</span> Feature Test
Macro<span></span></a></li>
</ul></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="r0"><span class="header-section-number">1.1</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 default">std::ranges::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 default">std::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 default">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 default">std::string_view</code>
<code class="sourceCode default">std::function</code> and
<code class="sourceCode default">std::function_ref</code>, and
<code class="sourceCode default">std::any</code> are the type-erased
facilities for the examples above.</p>
<p><code class="sourceCode default">std::span&lt;T&gt;</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 default">std::ranges::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 default">ranges::view</code> concept itself.
<code class="sourceCode default">std::ranges::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 default">any_view</code> raises a lot of
questions.</p>
<p>Let’s take <code class="sourceCode default">std::function</code> as
an example. At first, its interface seems extremely simple: it provides
<code class="sourceCode default">operator()</code> and users only need
to configure the return type and argument types of the function. In
reality, <code class="sourceCode default">std::function</code> makes
many other decisions for the user:</p>
<ul>
<li>Are <code class="sourceCode default">std::function</code> and the
callable it contains
<code class="sourceCode default">copyable</code>?</li>
<li>Does <code class="sourceCode default">std::function</code> own the
callable it contains?</li>
<li>Does <code class="sourceCode default">std::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 default">function</code></li>
<li><code class="sourceCode default">move_only_function</code></li>
<li><code class="sourceCode default">function_ref</code></li>
<li><code class="sourceCode default">copyable_function</code></li>
</ul>
<p>The design space of <code class="sourceCode default">any_view</code>
is a lot more complex than that:</p>
<ul>
<li>Is it an <code class="sourceCode default">input_range</code>,
<code class="sourceCode default">forward_range</code>,
<code class="sourceCode default">bidirectional_range</code>,
<code class="sourceCode default">random_access_range</code>, or a
<code class="sourceCode default">contiguous_range</code> ?</li>
<li>Is the range <code class="sourceCode default">copyable</code> ?</li>
<li>Is it a <code class="sourceCode default">sized_range</code> ?</li>
<li>Is it a <code class="sourceCode default">borrowed_range</code>
?</li>
<li>Is it a <code class="sourceCode default">common_range</code> ?</li>
<li>What is the
<code class="sourceCode default">range_reference_t</code> ?</li>
<li>What is the <code class="sourceCode default">range_value_t</code>
?</li>
<li>What is the
<code class="sourceCode default">range_rvalue_reference_t</code> ?</li>
<li>What is the
<code class="sourceCode default">range_difference_t</code> ?</li>
<li>Is the <code class="sourceCode default">range</code>
const-iterable?</li>
<li>Is the iterator <code class="sourceCode default">copyable</code> for
<code class="sourceCode default">input_iterator</code>?</li>
<li>Is the iterator equality comparable for
<code class="sourceCode default">input_iterator</code>?</li>
<li>Do the iterator and sentinel types satisfy
<code class="sourceCode default">sized_sentinel_for&lt;S, I&gt;</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 default">std::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 default">boost::ranges::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 default">range_reference_t</code>,
<code class="sourceCode default">range_value_t</code> and
<code class="sourceCode default">range_difference_t</code>.
<code class="sourceCode default">Traversal</code> is equivalent to
<code class="sourceCode default">iterator_concept</code>, which decides
the traversal category of the range. Users don’t need to specify
<code class="sourceCode default">copyable</code>,
<code class="sourceCode default">borrowed_range</code> and
<code class="sourceCode default">common_range</code>, because all
Boost.Range ranges are <code class="sourceCode default">copyable</code>,
<code class="sourceCode default">borrowed_range</code> and
<code class="sourceCode default">common_range</code>.
<code class="sourceCode default">sized_range</code> and
<code class="sourceCode default">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 default">ranges::views::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 default">Cat</code> handles both the
traversal category and
<code class="sourceCode default">sized_range</code>.
<code class="sourceCode default">Ref</code> is the
<code class="sourceCode default">range_reference_t</code>. It does not
allow users to configure the
<code class="sourceCode default">range_value_t</code>,
<code class="sourceCode default">range_difference_t</code>,
<code class="sourceCode default">borrowed_range</code> and
<code class="sourceCode default">common_range</code>.
<code class="sourceCode default">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> Value,</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> Value <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> 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-17"><a href="#cb6-17" 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-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> any_view <span class="op">{</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> iterator; <span class="co">// exposition-only</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> sentinel; <span class="co">// exposition-only</span></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-22"><a href="#cb6-22" 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-23"><a href="#cb6-23" 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-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a>             view_options_constraint<span class="op">&lt;</span>View<span class="op">&gt;())</span></span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a>  any_view<span class="op">(</span>View view<span class="op">)</span>;</span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-27"><a href="#cb6-27" 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-28"><a href="#cb6-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-29"><a href="#cb6-29" 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-30"><a href="#cb6-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-31"><a href="#cb6-31" 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-32"><a href="#cb6-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-33"><a href="#cb6-33" 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-34"><a href="#cb6-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-35"><a href="#cb6-35" aria-hidden="true" tabindex="-1"></a>  iterator begin<span class="op">()</span>;</span>
<span id="cb6-36"><a href="#cb6-36" aria-hidden="true" tabindex="-1"></a>  sentinel end<span class="op">()</span>;</span>
<span id="cb6-37"><a href="#cb6-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-38"><a href="#cb6-38" 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-39"><a href="#cb6-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb6-40"><a href="#cb6-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-41"><a href="#cb6-41" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Value, any_view_options Opts, <span class="kw">class</span> Ref, <span class="kw">class</span> RValueRef,</span>
<span id="cb6-42"><a href="#cb6-42" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Diff<span class="op">&gt;</span></span>
<span id="cb6-43"><a href="#cb6-43" 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-44"><a href="#cb6-44" 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-45"><a href="#cb6-45" 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 default">any_view</code> by
<code class="sourceCode default">bitwise-or</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, std<span class="op">::</span>ranges<span class="op">::</span>any_view_options<span class="op">::</span>bidirectional <span class="op">|</span> 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="other-design-considerations"><span class="header-section-number">6</span> Other Design Considerations<a href="#other-design-considerations" class="self-link"></a></h1>
<h2 data-number="6.1" id="should-the-first-argument-be-ref-or-value"><span class="header-section-number">6.1</span> Should the first argument be
<code class="sourceCode default">Ref</code> or
<code class="sourceCode default">Value</code>?<a href="#should-the-first-argument-be-ref-or-value" class="self-link"></a></h2>
<p>If the first template parameter is
<code class="sourceCode default">Ref</code>, we have:</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><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> Ref,</span>
<span id="cb8-2"><a href="#cb8-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="cb8-3"><a href="#cb8-3" 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;&gt;</span></span></code></pre></div>
<p>For a range with a reference to
<code class="sourceCode default">int</code>, one would write</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><span class="dt">int</span><span class="op">&amp;&gt;</span></span></code></pre></div>
<p>And for a <code class="sourceCode default">const</code> reference to
<code class="sourceCode default">int</code>, one would write</p>
<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>any_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">int</span><span class="op">&amp;&gt;</span></span></code></pre></div>
<p>In case of a generator range, e.g a
<code class="sourceCode default">transform_view</code> which generates
pr-value <code class="sourceCode default">int</code>, the usage would
be</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>any_view<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></span></code></pre></div>
<p>However, it is possible that the user uses
<code class="sourceCode default">any_view&lt;string&gt;</code> without
realizing that they specified the reference type and they now make a
copy of the <code class="sourceCode default">string</code> every time
when the iterator is dereferenced.</p>
<p>Instead, if the first template parameter is
<code class="sourceCode default">Value</code>, we have:</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">template</span> <span class="op">&lt;</span><span class="kw">class</span> Value,</span>
<span id="cb12-2"><a href="#cb12-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="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>          <span class="kw">class</span> Ref <span class="op">=</span> Value<span class="op">&amp;&gt;</span></span></code></pre></div>
<p>For a range with a reference to
<code class="sourceCode default">int</code>, it would be less
verbose</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>any_view<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></span></code></pre></div>
<p>However, in order to have a
<code class="sourceCode default">const</code> reference to
<code class="sourceCode default">int</code>, one would have to
explicitly specify the <code class="sourceCode default">Value</code>,
the any_view_options and finally the
<code class="sourceCode default">Ref</code>, i.e.</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>any_view<span class="op">&lt;</span><span class="dt">int</span>, any_view_options<span class="op">::</span>input, <span class="kw">const</span> <span class="dt">int</span><span class="op">&amp;&gt;</span></span></code></pre></div>
<p>This is a bit verbose. In the case of a generator range, one would
need to do the same:</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>any_view<span class="op">&lt;</span><span class="dt">int</span>, any_view_options<span class="op">::</span>input, <span class="dt">int</span><span class="op">&gt;</span></span></code></pre></div>
<p><strong>Author Recommendation</strong>: Even though the first option
is less verbose in few cases, it might create unnecessary copies without
user realizing it. The author recommends the second option.</p>
<h2 data-number="6.2" id="name-of-the-any_view_options"><span class="header-section-number">6.2</span> Name of the
<code class="sourceCode default">any_view_options</code><a href="#name-of-the-any_view_options" class="self-link"></a></h2>
<p><code class="sourceCode default">range-v3</code> uses the name
<code class="sourceCode default">category</code> for the category
enumeration type. However, the authors believe that the name
<code class="sourceCode default">std::ranges::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 default">any_view_options</code>.</p>
<h2 data-number="6.3" id="constexpr-support"><span class="header-section-number">6.3</span>
<code class="sourceCode default">constexpr</code> Support<a href="#constexpr-support" class="self-link"></a></h2>
<p>We do not require <code class="sourceCode default">constexpr</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 default">unsigned char[N]</code> or
<code class="sourceCode default">std::byte[N]</code> buffer in
<code class="sourceCode default">constexpr</code> context.</p>
<h2 data-number="6.4" id="move-only-view-support"><span class="header-section-number">6.4</span> Move-only
<code class="sourceCode default">view</code> Support<a href="#move-only-view-support" class="self-link"></a></h2>
<p>Move-only <code class="sourceCode default">view</code> is worth
supporting as we generally support them in
<code class="sourceCode default">ranges</code>. We propose to have a
configuration template parameter
<code class="sourceCode default">any_view_options::move_only</code> to
make the <code class="sourceCode default">any_view</code> conditionally
move-only. This removes the need to have another type
<code class="sourceCode default">move_only_any_view</code> as we did for
<code class="sourceCode default">move_only_function</code>.</p>
<p>We also propose that by default,
<code class="sourceCode default">any_view</code> is copyable and to make
it move-only, the user needs to explicitly provide this template
parameter
<code class="sourceCode default">any_view_options::move_only</code>.</p>
<h2 data-number="6.5" id="move-only-iterator-support"><span class="header-section-number">6.5</span> Move-only
<code class="sourceCode default">iterator</code> Support<a href="#move-only-iterator-support" class="self-link"></a></h2>
<p>In this proposal,
<code class="sourceCode default">any_view::iterator</code> is an
exposition-only type. It is not worth making this
<code class="sourceCode default">iterator</code> configurable. If the
<code class="sourceCode default">iterator</code> is only
<code class="sourceCode default">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="6.6" id="is-any_view_optionscontiguous-needed"><span class="header-section-number">6.6</span> Is
<code class="sourceCode default">any_view_options::contiguous</code>
Needed ?<a href="#is-any_view_optionscontiguous-needed" class="self-link"></a></h2>
<p><code class="sourceCode default">contiguous_range</code> is still
useful to support even though we have already
<code class="sourceCode default">std::span</code>. But
<code class="sourceCode default">span</code> is non-owning and
<code class="sourceCode default">any_view</code> owns the underlying
<code class="sourceCode default">view</code>.</p>
<h2 data-number="6.7" id="is-any_view-const-iterable"><span class="header-section-number">6.7</span> Is
<code class="sourceCode default">any_view</code> const-iterable?<a href="#is-any_view-const-iterable" class="self-link"></a></h2>
<p>We cannot make <code class="sourceCode default">any_view</code>
unconditionally const-iterable. If we did,
<code class="sourceCode default">views</code> with cache-on-begin, like
<code class="sourceCode default">filter_view</code> and
<code class="sourceCode default">drop_while_view</code> could no longer
be put into an <code class="sourceCode default">any_view</code>.</p>
<p>One option would be to make
<code class="sourceCode default">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 default">Ref</code> and
<code class="sourceCode default">RValueRef</code> can be different
between <code class="sourceCode default">const</code> and
non-<code class="sourceCode default">const</code> iterators.</p>
<p>For simplicity, the authors propose to make
<code class="sourceCode default">any_view</code> unconditionally
non-const-iterable.</p>
<h2 data-number="6.8" id="common_range-support"><span class="header-section-number">6.8</span>
<code class="sourceCode default">common_range</code> support<a href="#common_range-support" class="self-link"></a></h2>
<p>Unconditionally making
<code class="sourceCode default">any_view</code> a
<code class="sourceCode default">common_range</code> is not an option.
This would exclude most of the Standard Library
<code class="sourceCode default">view</code>s. Adding a configuration
template parameter to make
<code class="sourceCode default">any_view</code> conditionally
<code class="sourceCode default">common_range</code> is overkill. After
all, if users need <code class="sourceCode default">common_range</code>,
they can use
<code class="sourceCode default">my_any_view | views::common</code>.
Furthermore, supporting this turns out to add substantial complexity in
the implementation. The authors believe that adding
<code class="sourceCode default">common_range</code> support is not
worth the added complexity.</p>
<h2 data-number="6.9" id="borrowed_range-support"><span class="header-section-number">6.9</span>
<code class="sourceCode default">borrowed_range</code> support<a href="#borrowed_range-support" class="self-link"></a></h2>
<p>Having support for
<code class="sourceCode default">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 default">enable_borrowed_range</code> if the
template parameter is set to
<code class="sourceCode default">true</code></li>
</ol></li>
</ul>
<p>Therefore, we recommend conditional support for
<code class="sourceCode default">borrowed_range</code>. However, since
<code class="sourceCode default">borrowed_range</code> is not a very
useful concept in general, this design point is open for discussion.</p>
<h2 data-number="6.10" id="valueless-state-of-any_view"><span class="header-section-number">6.10</span> Valueless state of
<code class="sourceCode default">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 default">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 default">noexcept</code>, the only way to
achieve the strong exception safety guarantee is to avoid calling these
operations altogether, which requires
<code class="sourceCode default">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 default">any_view</code> will have an empty
state, and a “moved-from”
<code class="sourceCode default">any_view</code> will be in that
state.</p>
<h2 data-number="6.11" id="abi-stability"><span class="header-section-number">6.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 default">any_view</code> is
extremely important. However, since almost any change to the API of
<code class="sourceCode default">any_view</code> will require a
modification to the vtable, this makes
<code class="sourceCode default">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 default">any_view</code>, this
evolutionary challenge should be kept in mind by WG21.</p>
<h2 data-number="6.12" id="performance"><span class="header-section-number">6.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 default">any_view</code>, every iteration will
have three indirect function calls:</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="op">++</span>it;</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>it <span class="op">!=</span> last;</span>
<span id="cb16-3"><a href="#cb16-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 default">any_view</code> is
used and what the alternatives to it are.</p>
<h3 data-number="6.12.1" id="a-naive-micro-benchmark-iteration-over-vector-vs-any_view"><span class="header-section-number">6.12.1</span> A naive micro benchmark:
iteration over <code class="sourceCode default">vector</code> vs
<code class="sourceCode default">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 default">std::vector</code> and to compare it
with the cost of iterating over
<code class="sourceCode default">any_view</code>. For example, the
following code:</p>
<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>  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="cb17-2"><a href="#cb17-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="cb17-3"><a href="#cb17-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="cb17-4"><a href="#cb17-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="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>vs</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>  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="cb18-2"><a href="#cb18-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="cb18-3"><a href="#cb18-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="cb18-4"><a href="#cb18-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="cb18-5"><a href="#cb18-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="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p><strong>-O0</strong></p>
<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                  +3.4488            10423                 46371</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                  +3.3358            21318                 92432</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                  +3.4224            41864                185137</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                  +3.4665            83019                370802</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                 +3.4586           166596                742785</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                 +3.4413           333311               1480349</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                 +3.4166           667125               2946432</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                +3.4295          1335405               5915230</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                +3.4320          2665004              11811264</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                  +3.4278                0                     0</span></code></pre></div>
<p><strong>-O2</strong></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 vector      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_vector</span> vs. BM_AnyView]/1024                 +14.8383             315               4991</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/2048                 +14.9416             632              10075</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/4096                 +15.1943            1231              19942</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/8192                 +15.1609            2465              39835</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/16384                +13.8958            5386              80235</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/32768                +13.8638           10720             159341</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/65536                +13.6891           21772             319807</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/131072               +13.5340           44363             644768</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_vector</span> vs. BM_AnyView]/262144               +13.5374           87600            1273476</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                 +16.0765               0                  0</span></code></pre></div>
<p>We can see that <code class="sourceCode default">any_view</code> is 3
to 16 times slower on iteration than
<code class="sourceCode default">std::vector</code>. However, this
benchmark is not a realistic use case. No one would create a
<code class="sourceCode default">vector</code>, immediately create a
type erased wrapper <code class="sourceCode default">any_view</code>
that wraps it and then iterate through it. Similarly, no one would
create a lambda, immediately create a
<code class="sourceCode default">std::function</code> and then call
it.</p>
<h3 data-number="6.12.2" id="a-slightly-more-realistic-benchmark-a-view-pipeline-vs-any_view"><span class="header-section-number">6.12.2</span> A slightly more realistic
benchmark: A view pipeline vs
<code class="sourceCode default">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 default">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 default">any_view</code> are expected to be with
non-trivial view pipelines, not with e.g. a raw
<code class="sourceCode default">std::vector</code>. As the pipeline
increases in complexity, the relative cost of using
<code class="sourceCode default">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 default">any_view</code> or with the pipeline’s
actual type:</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="co">// header file</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Widget <span class="op">{</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string name;</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> size;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UI <span class="op">{</span></span>
<span id="cb19-8"><a href="#cb19-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="cb19-9"><a href="#cb19-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="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="co">// cpp file</span></span>
<span id="cb19-13"><a href="#cb19-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="cb19-14"><a href="#cb19-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="cb19-15"><a href="#cb19-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="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>         <span class="op">})</span> <span class="op">|</span></span>
<span id="cb19-17"><a href="#cb19-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="cb19-18"><a href="#cb19-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="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-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="cb20-2"><a href="#cb20-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="cb20-3"><a href="#cb20-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="cb20-4"><a href="#cb20-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="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span></code></pre></div>
<p>In the <code class="sourceCode default">any_view</code> case, we
simply replace <code class="sourceCode default">std::ranges::transform_view&lt;complicated...&gt;</code>
by <code class="sourceCode default">std::ranges::any_view</code> and we
measure the same thing.</p>
<p><strong>-O0</strong></p>
<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 complicated    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_RawPipeline</span> vs. BM_AnyViewPipeline]/1024                  +0.4290                 78469           112130</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/2048                  +0.4051                159225           223729</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/4096                  +0.3568                331276           449466</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/8192                  +0.4022                639566           896817</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/16384                 +0.4148               1267196          1792804</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/32768                 +0.4293               2522849          3606022</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/65536                 +0.4199               5078713          7211428</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/131072                +0.4170              10142694         14372118</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/262144                +0.4358              20386564         29270816</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                               +0.4120                     0                0</span></code></pre></div>
<p><strong>-O2</strong></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 complicated    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_RawPipeline</span> vs. BM_AnyViewPipeline]/1024                  +0.8066                  3504             6330</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/2048                  +0.7136                  7339            12576</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/4096                  +0.6746                 14841            24853</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/8192                  +0.6424                 30177            49563</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/16384                 +0.6538                 60751           100468</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/32768                 +0.6524                121345           200514</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/65536                 +0.6582                240378           398604</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/131072                +0.6861                484220           816458</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_RawPipeline</span> vs. BM_AnyViewPipeline]/262144                +0.6234                991733          1609940</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                               +0.6782                     0                0</span></code></pre></div>
<p>This benchmark shows that
<code class="sourceCode default">any_view</code> is about 40% - 70%
slower on iteration, which is much better than the previous naive
benchmark. However, note that this benchmark is still not very
realistic. First, the type of the view pipeline is in fact so difficult
to write that nobody would do it. Second, 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, which is
undesirable.</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 default">getWidgetNames()</code>, for example as
a
<code class="sourceCode default">std::vector&lt;std::string&gt;</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="6.12.3" id="a-realistic-benchmark-a-copy-of-vectorstring-vs-any_view"><span class="header-section-number">6.12.3</span> A realistic benchmark: A
copy of <code class="sourceCode default">vector&lt;string&gt;</code> vs
<code class="sourceCode default">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 default">std::vector</code> as a type erasure
tool for lack of a better tool. Such code would look like this:</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><span class="co">// header file</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UI <span class="op">{</span></span>
<span id="cb21-3"><a href="#cb21-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="cb21-4"><a href="#cb21-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="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a><span class="co">// cpp file</span></span>
<span id="cb21-8"><a href="#cb21-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="cb21-9"><a href="#cb21-9" 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="cb21-10"><a href="#cb21-10" 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="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>         <span class="op">})</span> <span class="op">|</span></span>
<span id="cb21-12"><a href="#cb21-12" 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 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="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>-O0</strong></p>
<div class="sourceCode" id="cb5"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                                       Time      Time vector<span class="op">&lt;</span>string<span class="op">&gt;</span>    Time any_view</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="ex">--------------------------------------------------------------------------------------------------------------</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/1024                  <span class="at">-0.5376</span>                   238558           110316</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/2048                  <span class="at">-0.5110</span>                   454350           222187</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/4096                  <span class="at">-0.4868</span>                   886121           454774</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/8192                  <span class="at">-0.4766</span>                  1729318           905041</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/16384                 <span class="at">-0.4834</span>                  3462454          1788737</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/32768                 <span class="at">-0.4858</span>                  7006102          3602475</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/65536                 <span class="at">-0.4777</span>                 13741174          7176723</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/131072                <span class="at">-0.4792</span>                 27501856         14321826</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/262144                <span class="at">-0.4838</span>                 55950048         28883803</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                              <span class="at">-0.4917</span>                        0                0</span></code></pre></div>
<p><strong>-O2</strong></p>
<div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">Benchmark</span>                                                       Time      Time vector<span class="op">&lt;</span>string<span class="op">&gt;</span>    Time any_view</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="ex">--------------------------------------------------------------------------------------------------------------</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/1024                  <span class="at">-0.8228</span>                    35350             6264</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/2048                  <span class="at">-0.8250</span>                    71983            12596</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/4096                  <span class="at">-0.8320</span>                   148942            25018</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/8192                  <span class="at">-0.8276</span>                   291307            50234</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/16384                 <span class="at">-0.8304</span>                   590026           100058</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/32768                 <span class="at">-0.8301</span>                  1175121           199685</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/65536                 <span class="at">-0.8297</span>                  2363963           402634</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/131072                <span class="at">-0.8340</span>                  4841300           803467</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="ex">[BM_VectorCopy</span> vs. BM_AnyViewPipeline]/262144                <span class="at">-0.8463</span>                 10412999          1600341</span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="ex">OVERALL_GEOMEAN</span>                                              <span class="at">-0.8310</span>                        0                0</span></code></pre></div>
<p>With this more realistic use case, we can see that
<code class="sourceCode default">any_view</code> is 50% - 80% faster. In
our benchmark, 10% of the
<code class="sourceCode default">Widget</code>s were filtered out by the
filter pipeline and the <code class="sourceCode default">name</code>
string’s length is randomly 0-30. So some of
<code class="sourceCode default">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 default">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 optimziations like selective
devirtualization of some common operations like
<code class="sourceCode default">for_each</code> to achieve large
performance gains in specific cases.</p>
<h1 data-number="7" id="implementation-experience"><span class="header-section-number">7</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h1>
<p><code class="sourceCode default">any_view</code> has been implemented
in <span class="citation" data-cites="rangev3">[<a href="#ref-rangev3" 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="#ref-ours" role="doc-biblioref">ours</a>]</span>.</p>
<h1 data-number="8" id="wording"><span class="header-section-number">8</span> Wording<a href="#wording" class="self-link"></a></h1>
<h2 data-number="8.1" id="feature-test-macro"><span class="header-section-number">8.1</span> Feature Test Macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>```</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" 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 default">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>
