<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3494: Allow ranges to be conditionally borrowed</title>
<meta property="og:title" content="Issue 3494: Allow ranges to be conditionally borrowed">
<meta property="og:description" content="C++ library issue. Status: C++23">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3494.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++23">C++23</a> status.</em></p>
<h3 id="3494"><a href="lwg-defects.html#3494">3494</a>. Allow ranges to be conditionally borrowed</h3>
<p><b>Section:</b> 25.7.21 <a href="https://wg21.link/range.reverse">[range.reverse]</a>, 25.7.10 <a href="https://wg21.link/range.take">[range.take]</a>, 25.7.12 <a href="https://wg21.link/range.drop">[range.drop]</a>, 25.7.13 <a href="https://wg21.link/range.drop.while">[range.drop.while]</a>, 25.7.20 <a href="https://wg21.link/range.common">[range.common]</a>, 25.7.13 <a href="https://wg21.link/range.drop.while">[range.drop.while]</a>, 25.7.23 <a href="https://wg21.link/range.elements">[range.elements]</a> <b>Status:</b> <a href="lwg-active.html#C++23">C++23</a>
 <b>Submitter:</b> Barry Revzin <b>Opened:</b> 2020-11-01 <b>Last modified:</b> 2023-11-22</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#range.reverse">issues</a> in [range.reverse].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++23">C++23</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Consider the following approach to trimming a <code>std::string</code>:
</p>
<blockquote><pre>
auto trim(std::string const&amp; s) {
  auto isalpha = [](unsigned char c){ return std::isalpha(c); };
  auto b = ranges::find_if(s, isalpha);
  auto e = ranges::find_if(s | views::reverse, isalpha).base();
  return subrange(b, e);
}
</pre></blockquote>
<p>
This is a fairly nice and, importantly, safe way to implement <code>trim</code>. The iterators <code>b</code>
and <code>e</code> returned from <code>find_if</code> will not dangle, since they point into the <code>string s</code>
whose lifetime outlives the function. But the status quo in C++20 is that <code>s | views::reverse</code>
is not a borrowed range (because <code>reverse_view&lt;V&gt;</code> is never a borrowed range for any <code>V</code>).
As a result, <code>find_if(s | views::reverse, isalpha)</code> returns <em>dangling</em> rather than
a real iterator.
<p/>
Instead, you have to write it this way, introducing a new named variable for the reversed view:
</p>
<blockquote><pre>
auto trim(std::string const&amp; s) {
  auto isalpha = [](unsigned char c){ return std::isalpha(c); };
  auto b = ranges::find_if(s, isalpha);
  auto reversed = s | views::reverse;
  auto e = ranges::find_if(reversed, isalpha).base();
  return subrange(b, e);
}
</pre></blockquote>
<p>
But borrowed range can be a transitive property. <code>s</code> itself is a borrowed range (as all
lvalue references are) so <code>s | views::reverse</code> could be made to be too, which would allow
the first example above to work with really no downside. We know such an iterator would not dangle,
we just need to teach the library this.
<p/>
<a href="https://wg21.link/p2017R1">P2017R1</a> resolves this by making <code>reverse_view&lt;V&gt;</code>
a borrowed range when <code>V</code> is a borrowed range (and likewise several other range adapters).
</p>

<p><i>[2021-01-15; Telecon prioritization]</i></p>

<p>
Set status to Tentatively Ready after five P0 votes in reflector discussion.
</p>

<p><i>[2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready &rarr; WP.]</i></p>



<p><b>Rationale:</b></p>
Resolved by <a href="https://wg21.link/p2017R1">P2017R1</a>.


<p id="res-3494"><b>Proposed resolution:</b></p>





</body>
</html>
