<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-12-14" />
  <title>Extending Conditionally Borrowed</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">Extending Conditionally
Borrowed</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3117R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-12-14</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG-9<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Zach Laine<br>&lt;<a href="mailto:whatwasthataddress@gmail.com" class="email">whatwasthataddress@gmail.com</a>&gt;<br>
      Jonathan Müller<br>&lt;<a href="mailto:jonathanmueller.dev@gmail.com" class="email">jonathanmueller.dev@gmail.com</a>&gt;<br>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@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="#changelog" id="toc-changelog"><span class="toc-section-number">1</span> Changelog<span></span></a>
<ul>
<li><a href="#changes-since-r0" id="toc-changes-since-r0"><span class="toc-section-number">1.1</span> Changes since
R0<span></span></a></li>
</ul></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation<span></span></a></li>
<li><a href="#why-care-about-borrowed_range" id="toc-why-care-about-borrowed_range"><span class="toc-section-number">3</span> Why care about
<code class="sourceCode default">borrowed_range</code>?<span></span></a></li>
<li><a href="#status-quo" id="toc-status-quo"><span class="toc-section-number">4</span> Status quo<span></span></a></li>
<li><a href="#proposed-change" id="toc-proposed-change"><span class="toc-section-number">5</span> Proposed change<span></span></a>
<ul>
<li><a href="#create-implementation-only-trait" id="toc-create-implementation-only-trait"><span class="toc-section-number">5.1</span> Create implementation-only
trait<span></span></a></li>
<li><a href="#transform_view" id="toc-transform_view"><span class="toc-section-number">5.2</span>
<code class="sourceCode default">transform_view</code><span></span></a>
<ul>
<li><a href="#abi-concerns" id="toc-abi-concerns"><span class="toc-section-number">5.2.1</span> ABI
concerns<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">6</span> Implementation
experience<span></span></a></li>
<li><a href="#costs-versus-benefits" id="toc-costs-versus-benefits"><span class="toc-section-number">7</span>
Costs versus benefits<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">8</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="changelog"><span class="header-section-number">1</span> Changelog<a href="#changelog" class="self-link"></a></h1>
<h2 data-number="1.1" id="changes-since-r0"><span class="header-section-number">1.1</span> Changes since R0<a href="#changes-since-r0" class="self-link"></a></h2>
<ul>
<li>Remove changes for all views except
<code class="sourceCode default">transform_view</code>.</li>
<li>Completely change the strategy of the changes for maximum ABI
compatibility.</li>
</ul>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>In <span class="citation" data-cites="P2017R1">[<a href="#ref-P2017R1" role="doc-biblioref">P2017R1</a>]</span>, we made
some range adaptors conditionally borrowed. But we didn’t touch adaptors
that had callables - like
<code class="sourceCode default">views::transform</code>. It turns out
to be very useful to have a borrowable version of
<code class="sourceCode default">views::transform</code>. Indeed, <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2728r6.html">P2728R6</a>
even adds a dedicated new range adaptor
(<code class="sourceCode default">views::project</code>) which is simply
a version of <code class="sourceCode default">views::transform</code>
that can be borrowed (because its callable must be a constant).</p>
<p>But rather than add a dedicated view for this specific case, which
requires a new name but really only helps
<code class="sourceCode default">views::transform</code>, we can
generalize <code class="sourceCode default">views::transform</code> to
address the use-case in a way that would also help all the other range
adaptors that take callables. At the very least, in
<code class="sourceCode default">views::transform(r, f)</code> if
<code class="sourceCode default">r</code> is borrowed and
<code class="sourceCode default">f</code> is empty, an implementation
can simply put <code class="sourceCode default">f</code> in the <code class="sourceCode default">transform_view&lt;R, F&gt;::iterator</code>
directly (rather than a
<code class="sourceCode default">transform_view&lt;R, F&gt; *</code>)
which would allow it to be borrowed. The same could be said for other
range adaptors that take callables as well, which seems like a more
useful approach as well as not requiring new names for every
adaptor.</p>
<p>The main question then is what the criteria should be for when
<code class="sourceCode default">transform_view&lt;R, F&gt;</code>
should be a borrowed range (when
<code class="sourceCode default">R</code> is):</p>
<ul>
<li><p><code class="sourceCode default">is_empty_v&lt;F&gt;</code>
(range-v3 already does this - not for conditionally borrowed, but just
to decide whether to store the callable by value in the
iterator)</p></li>
<li><p><code class="sourceCode default">sizeof(F) &lt;= sizeof(void *)</code>
and
<code class="sourceCode default">is_trivially_copyable_v&lt;F&gt;</code>
(this means that when transforming with a function pointer, the function
pointer itself can live in the iterator - which takes the same amount of
space as the parent pointer, except with one less indirection)</p></li>
<li><p>something else?</p></li>
</ul>
<p>This question is a little simpler for
<code class="sourceCode default">views::transform</code> (which only
needs to potentially store <code class="sourceCode default">f</code> in
the adapted iterator) than it is for
<code class="sourceCode default">views::filter</code> (which would need
not only the predicate but also the underlying sentinel, so this may not
be worthwhile). This would need to be carefully considered.</p>
<h1 data-number="3" id="why-care-about-borrowed_range"><span class="header-section-number">3</span> Why care about
<code class="sourceCode default">borrowed_range</code>?<a href="#why-care-about-borrowed_range" class="self-link"></a></h1>
<p><code class="sourceCode default">borrowed_range</code> is important
because it allows the standard range adaptors and views to know that a
particular view is a proper view – that is, a reference type, not an
expensive-to-copy type like a
<code class="sourceCode default">std::vector&lt;int&gt;</code>. Certain
views refuse to work with
non-<code class="sourceCode default">borrowed_range</code> ranges,
because the result might dangle. For instance, you cannot construct a
<code class="sourceCode default">subrange</code> from a
non-<code class="sourceCode default">borrowed_range</code>. In other
cases, an rvalue range might be wrapped in a
<code class="sourceCode default">owning_view</code> to turn it into a
view, if it was not already a
<code class="sourceCode default">borrowed_range</code>. So <code class="sourceCode default">std::vector&lt;int&gt;({1,2,3,4,5,6,7,8,9}) | take(3)</code>
would take the rvalue <code class="sourceCode default">vector</code>,
wrap it in an <code class="sourceCode default">owning_view</code>, and
the result is a
non-<code class="sourceCode default">borrowed_range</code> that is
move-only.</p>
<p>Here is the part of <span>25.4.2
<a href="https://wg21.link/range.range">[range.range]</a></span> that
describes <code class="sourceCode default">borrowed_range</code>:</p>
<blockquote>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> borrowed_range <span class="op">=</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    range<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <span class="op">(</span>is_lvalue_reference_v<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">||</span> enable_borrowed_range<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>T<span class="op">&gt;&gt;)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let <code class="sourceCode default">U</code> be
<code class="sourceCode default">remove_reference_t&lt;T&gt;</code> if
<code class="sourceCode default">T</code> is an rvalue reference type,
and <code class="sourceCode default">T</code> otherwise. Given a
variable <code class="sourceCode default">u</code> of type
<code class="sourceCode default">U</code>,
<code class="sourceCode default">T</code> models
<code class="sourceCode default">borrowed_range</code> only if the
validity of iterators obtained from
<code class="sourceCode default">u</code> is not tied to the lifetime of
that variable.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
[<em>Note 2:</em> Since the validity of iterators is not tied to the
lifetime of a variable whose type models borrowed_range, a function with
a parameter of such a type can return iterators obtained from it without
danger of dangling. <em>? end note</em>]</p>
</blockquote>
<p>To increase the interoperability of the templates in
<code class="sourceCode default">std::ranges</code> and to avoid
unnecessary wrapping, we should make as many views
<code class="sourceCode default">borrowed_range</code>s as is
reasonable. It is probably unreasonable to do so if there is a
significant cost involved. To make a view a
<code class="sourceCode default">borrowed_range</code> means copying its
state out of the view itself, and into the iterator instead.</p>
<p>Note that copying state to the iterator is not sufficient to
guarantee borrowed-ness, though is it necessary. Most views take an
existing view <code class="sourceCode default">V</code> and do something
with it, making a new view over the existing one. For instance,
<code class="sourceCode default">transform_view&lt;V, F&gt;</code>
creates a view by transforming the elements of
<code class="sourceCode default">V</code> using the invocable
<code class="sourceCode default">F</code>.</p>
<p>A particular view specialization is only borrowed if it satisfies the
<code class="sourceCode default">borrowed_range</code> concept,
<em>and</em> <code class="sourceCode default">V</code> does as well.
This is important, because if a view is not borrowed, no view that uses
it will be either. In
<code class="sourceCode default">rng | V1 | V2 | ... | Vn</code>, if
<em>any</em> <code class="sourceCode default">Vi</code> is not borrowed,
the entire resulting view is not.</p>
<h1 data-number="4" id="status-quo"><span class="header-section-number">4</span> Status quo<a href="#status-quo" class="self-link"></a></h1>
<p>Currently, there are several views that are never
<code class="sourceCode default">borrowed_range</code>s that potentially
could be. They are:
<code class="sourceCode default">transform_view</code>,
<code class="sourceCode default">zip_transform_view</code>,
<code class="sourceCode default">adjacent_transform_view</code>,
<code class="sourceCode default">filter_view</code>,
<code class="sourceCode default">take_while_view</code>,
<code class="sourceCode default">chunk_by_view</code>,
<code class="sourceCode default">join_view</code>,
<code class="sourceCode default">join_with_view</code>,
<code class="sourceCode default">split_view</code>,
<code class="sourceCode default">lazy_split_view</code>, and
<code class="sourceCode default">cartesian_product_view</code>.</p>
<p>A previous version of this paper attempted to address the
borrowability of several of those views. The consensus in SG-9 was that,
since this would be a n ABI break for all of these views, that approach
was too ambitious. This version of the paper radically scales that
effort back; the plan now is to make a minimal change to
<code class="sourceCode default">transform_view</code>. If that change
can gain consensus in SG-9, we can proceed with more views, if
possible.</p>
<h1 data-number="5" id="proposed-change"><span class="header-section-number">5</span> Proposed change<a href="#proposed-change" class="self-link"></a></h1>
<p>All these changes are in
<code class="sourceCode default">std::ranges</code>.</p>
<h2 data-number="5.1" id="create-implementation-only-trait"><span class="header-section-number">5.1</span> Create implementation-only
trait<a href="#create-implementation-only-trait" class="self-link"></a></h2>
<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="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> F<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> <em>tidy-func</em> <span class="op">=</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    is_empty_v<span class="op">&lt;</span>F<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> is_trivially_default_constructible_v<span class="op">&lt;</span>F<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> is_trivially_destructible_v<span class="op">&lt;</span>F<span class="op">&gt;</span>;</span></code></pre></div>
<p><code class="sourceCode default"><em>tidy-func</em></code> evaluates
to <code class="sourceCode default">true</code> when an invocable is a
candidate for being re-created on the fly in a view’s iterators.</p>
<h2 data-number="5.2" id="transform_view"><span class="header-section-number">5.2</span>
<code class="sourceCode default">transform_view</code><a href="#transform_view" class="self-link"></a></h2>
<p>Change
<code class="sourceCode default">transform_view::iterator</code> to
create a new object of the type of
<code class="sourceCode default">transform_view</code>’s
<code class="sourceCode default">F</code> template parameter. That is,
the iterator will not reach back through the
<code class="sourceCode default">parent_</code> data member to get the
<code class="sourceCode default">fun_</code> member out of the view.
Also, add this specialization:</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><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> F<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> enable_borrowed_range<span class="op">&lt;</span>transform_view<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span> <span class="op">=</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    enable_borrowed_range<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span> <em>tidy-func</em><span class="op">&lt;</span>F<span class="op">&gt;</span>;</span></code></pre></div>
<p>This simple change means that, for any
<code class="sourceCode default">transform_view</code>
<code class="sourceCode default">tv</code> for which
<code class="sourceCode default">enable_borrowed_range</code> is
<code class="sourceCode default">true</code>, it is safe to use
<code class="sourceCode default">tv.begin()</code>/<code class="sourceCode default">tv.end()</code>
after the lifetime of <code class="sourceCode default">tv</code>. Even
though <code class="sourceCode default">tv.begin()</code> contains a
dangling pointer to <code class="sourceCode default">tv</code>, it will
never dereference that pointer.</p>
<h3 data-number="5.2.1" id="abi-concerns"><span class="header-section-number">5.2.1</span> ABI concerns<a href="#abi-concerns" class="self-link"></a></h3>
<p>This still poses an ABI problem, though it is much less likely to
affect real code than the change in the R0 revision of this paper. The
layout and even the values of data members is unchanged in
<code class="sourceCode default">transform_view</code>,
<code class="sourceCode default">transform_view::iterator</code>, and
<code class="sourceCode default">transform_view::sentinel</code>. So,
passing <code class="sourceCode default">transform_view</code>s and even
their iterator/sentinel pairs across an ABI boundary should be safe in
almost all cases – whichever side of the ABI boundary is using the
objects should use them in the right way. There is no ODR issue with
this change.</p>
<p>However, it is possible to construct a memory-unsafe usage across an
ABI boundary. New code, seeing that <code class="sourceCode default">is_borrowed_range&lt;transform_view&lt;...&gt;&gt;</code>
is <code class="sourceCode default">true</code>, might get rid of the
view, because it can. Then old code might try to use the dangling
<code class="sourceCode default">parent_</code> pointer:</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="co">// old_tu.cpp</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="co">// Code built with C++20 semantics.  Separately compiled, but with the types</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co">// and function declarations available in a header.</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> transform_foos<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span> <span class="op">&amp;</span> vec<span class="op">)</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>vec <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">(</span>some_f<span class="op">))</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> transformed_foos_t <span class="op">=</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">decltype</span><span class="op">(</span>transform_foos<span class="op">(</span>std<span class="op">::</span>declval<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span> <span class="op">&amp;&gt;()))</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> print_transformed_range<span class="op">(</span>transformed_foos_t<span class="op">::</span>iterator f, transformed_foos_t<span class="op">::</span>sentinel l<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> it <span class="op">=</span> f; it <span class="op">!=</span> l; <span class="op">++</span>it<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="op">*</span>it <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<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="co">// new_tu.cpp</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co">// Code built with post-P3117 semantics.</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> new_using_func<span class="op">()</span> <span class="op">{</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> r <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>subrange<span class="op">(</span>transform_foos<span class="op">(</span>get_vec<span class="op">()))</span>;  <span class="co">// leaves parent_ to dangle</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Uses F{} to get the predicate in the iterator.  OK.</span></span>
<span id="cb5-7"><a href="#cb5-7" 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> r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> i <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Runs in old_tu.cpp. Tries to use parent_-&gt;pred_, but parent_ is</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">// dangling.  UB.</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>    print_transformed_range<span class="op">(</span>r<span class="op">.</span>begin<span class="op">()</span>, r<span class="op">.</span>end<span class="op">())</span>;</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>There are a number of unlikely conditions that must exist for the
user to write this unsafe code.</p>
<ol type="1">
<li><p>It is difficult to name the types of
<code class="sourceCode default">std</code> views and their iterators.
As you can see above, we had to make a separate function that creates
the <code class="sourceCode default">transform_view</code> to make it
easier to get a typename for it.</p></li>
<li><p>The user must pass an iterator/sentinel pair to the old TU (as
above), or possibly put the iterator/sentinel pair into a
<code class="sourceCode default">subrange</code>. Passing the entire
<code class="sourceCode default">transform_view</code> to a function
means that it will outlive its iterators. Passing a
<code class="sourceCode default">subrange</code> is possible, but
unlikely – it you wanted to pass the iterator/sentinel pair as a range,
you would probably just pass the
<code class="sourceCode default">transform_view</code>.</p></li>
<li><p>The potential danger of this case is limited to the <code class="sourceCode default">is_borrowed_range&lt;Expr&gt; == true</code>
case, which is affected by the borrowability of all ranges and views in
the view expression <code class="sourceCode default">Expr</code>. In
other words, the proposed changes to
<code class="sourceCode default">transform_view</code> will make it
borrowable, but the danger above is only present if
<code class="sourceCode default">transform_view</code> is actually used
in a fully-borrowed view expression.</p></li>
</ol>
<p>This kind of failure is the bad kind – it is memory unsafe, and
leaves no lexical trace of its unsafety. However, it is also exceedingly
unlikely that the user will find themself in this situation.</p>
<h1 data-number="6" id="implementation-experience"><span class="header-section-number">6</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>One of the authors implemented the changes suggested above. The
implementation was done by taking the libstdc++ implementations, copying
them into a new header, in a new new namespace under
<code class="sourceCode default">std::ranges</code>, and altering them.
The implementation can be found <a href="https://github.com/tzlaine/small_wg1_papers/tree/master/conditionally_borrowed">here</a>.
The header is accompanied by a test file, and a small perf test. The
implementation was very straightforward.</p>
<h1 data-number="7" id="costs-versus-benefits"><span class="header-section-number">7</span> Costs versus benefits<a href="#costs-versus-benefits" class="self-link"></a></h1>
<p>TODO: No real change expected; run the perf tests to be sure.</p>
<h1 data-number="8" id="bibliography"><span class="header-section-number">8</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-P2017R1" class="csl-entry" role="doc-biblioentry">
[P2017R1] Barry Revzin. 2020-02-19. Conditionally borrowed ranges. <a href="https://wg21.link/p2017r1"><div class="csl-block">https://wg21.link/p2017r1</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
