<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title><code>ranges::to&lt;view&gt;</code></title>
  <style type="text/css">
    body {
      font-variant-ligatures: none;
    }

    p {
      text-align: justify
    }

    li {
      text-align: justify
    }

    blockquote.note,
    div.note {
      background-color: #E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
    }

    p code {
      color: navy
    }

    ins p code {
      color: #00A000
    }

    p ins code {
      color: #00A000
    }

    p del code {
      color: #A00000
    }

    ins {
      color: #00A000
    }

    del {
      color: #A00000
    }

    table#boilerplate {
      border: 0
    }

    table#boilerplate td {
      padding-left: 2em
    }

    table.bordered,
    table.bordered th,
    table.bordered td {
      border: 1px solid;
      text-align: center;
    }

    ins.block {
      color: #00A000;
      text-decoration: none
    }

    del.block {
      color: #A00000;
      text-decoration: none
    }

    #hidedel:checked~* del,
    #hidedel:checked~* del * {
      display: none;
      visibility: hidden
    }
  </style>
</head>

<body data-new-gr-c-s-check-loaded="14.1043.0" data-gr-ext-installed="">
  <table id="boilerplate">
    <tbody>
      <tr>
        <td>Document number</td>
        <td>P3544R0</td>
      </tr>
      <tr>
        <td>Date</td>
        <td>2025-02-11</td>
      </tr>
      <tr>
        <td>Audience</td>
        <td>SG9 (Ranges)</td>
      </tr>
      <tr>
        <td>Reply-to</td>
        <td>Hewill Kang &lt;hewillk@gmail.com&gt;</td>
      </tr>
    </tbody>
  </table>
  <hr>
  <h1><code>ranges::to&lt;view&gt;</code></h1>
  <ul>
    <li>
      <ul>
        <li>Abstract</li>
        <li>Revision history</li>
        <li>Motivation</li>
        <li>Discussion</li>
        <li>Proposed change</li>
      </ul>
    </li>
  </ul>
  <a name="Abstract"></a>
  <h2>Abstract</h2>
  <p>
    This paper proposes to remove the constraint that <code>ranges::to</code> requires the target object not to be a
    <code>view</code>.
  </p>
  <a name="Revision history"></a>
  <h2>Revision history</h2>
  <p>
  <h3>R0</h3>
  <p>Initial revision.</p>
  </p>
  </ol>
  </p>
  <a name="Motivation"></a>
  <h2>Motivation</h2>
  <p>
    The requirement for <code>ranges::to</code> that the target object <code>C</code> should satisfy
    <code>input_range</code> was removed in
    <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1206r4.pdf">P1206</a>R4, subsequently,
    LWG <a href="https://cplusplus.github.io/LWG/issue3785">3785</a> verified that such relaxation was intentional.
  </p>
  <p>
    Among them, Barry gave an example of using
    <code>ranges::to&lt;expected&gt;</code> to transform <code>vertor&lt;expected&gt;</code> into
    <code>expected&lt;vertor&gt;</code>.
    Although currently <code>expected</code> does not have such a constructor, the example itself is indeed reasonable.
  </p>
  <p>However, <code>ranges::to </code> still require that <code>C</code> cannot be a <code>view</code>, even though
    <code>C</code> now can
    be <i>any</i> class type.
    This constraint excludes very useful cases, chief among which is collecting split subranges into a
    <code>vertor&lt;string_view&gt;</code>:
  </p>
  <pre>
      auto ints = "1.2.3.4"sv
                | views::split('.')
                | ranges::to&lt;vector&lt;string_view&gt;&gt;(); // <span style="color:red;font-weight:bolder">error</span></pre>
  Above, <code>ranges::to</code> recursively calls itself to construct <code>string_view</code> via
  <code>ranges::to&lt;string_view&gt;</code>, which is currently forbidden. However, this works:
  <pre>
      auto ints = "1.2.3.4"sv
                | views::split('.')
                | ranges::to&lt;vector&gt;(); // <span style="color:#00A000;font-weight:bolder">ok</span></pre>
  <p>As CTAD deduces that the element type is <code>subrange</code>, there is really no
    difference between the
    two IMO. To achieve the first, we need a redundant lambda:</p>
  <pre>
      auto ints = "1.2.3.4"sv
                | views::split('.')
                | views::transform([](auto r) { return string_view(r); })
                | ranges::to&lt;vector&gt;(); // <span style="color:#00A000;font-weight:bolder">ok</span></pre>
  <p>
    This is frustrating, it would be great if the first case could work <i>naturally</i>.
    Even more unfortunately, compared to the <code>string_view</code> case, the following code is well-formed in
    the current
    standard:
  <pre>
      auto ints = "1.2.3.4"sv
                | views::split('.')
                | ranges::to&lt;vector&lt;span&lt;const char&gt;&gt;&gt;(); // <span style="color:#00A000;font-weight:bolder">ok in the current standard!!!</span></pre>
  </pre>
  <p>
    This is because the <code>span</code>'s range constructor is not <code>explicit</code>, so
    <code>subrange</code> can be implicitly converted
    to <code>span</code>, which in turn that <code>vector&lt;span&lt;const char&gt;&gt;</code> can be directly
    constructed
    from a range whose elements are <code>subrange</code>s of <code>char</code> via range-tag
    constructor,
    without recursively going through <code>ranges::to</code>!
  </p>
  <p>Such inconsistency is quite unsatisfactory, as splitting strings (whether via
    <code>split</code>, <code>slide</code>, <code>chunk</code>, <code>chunk_by</code>, etc.) into
    <code>string_view</code>s is usually a
    common usage.
  </p>
  <p></p>
  </p>
  <a name="Discussion"></a>
  <h2>Discussion</h2>
  <p>Now, the question becomes:
    why did we require that the the target type cannot be a <code>view</code> in the
    first
    place?
    I believe this may be due to preventing users from making views this way or for safety concerns.
  </p>
  <p>For the first case, it makes sense to me for those in
    <code>&lt;ranges&gt;</code> but
    not
    for <code>string_view</code>/<code>span</code>, given that <code>ranges::to&lt;string_view&gt;</code> is indeed an
    intuitive spelling.
    Even so, this constraint does not block <code>gsl::span</code>,
    <code>ranges::v3::<i>moew</i>_view</code>, or even
    <code>tuple&lt;<i>some-view-types</i>&gt</code> since
    those are not model <code>ranges::view</code>.
  </p>
  <p>I don't think any user would want to use <code>ranges::to</code> to construct <code>take_view</code> instead of
    just spell <code>views::take</code>, but even if they did, it wouldn't cause harm that warrants a special
    prohibition, just as the standard doesn't disallow the view's constructor for users.
  </p>
  <p>
    If the purpose is to prevent dangling, it is indeed worth thinking about.
    Because in the current standard, <code>string_view</code> is allowed to be constructed from <i>rvalue</i>
    <code>string</code>,
    which means that if there is no such restriction, then <code>ranges::to&lt;string_view&gt;(string("abc"))</code>
    will be well-formed and definitely dangling.
  </p>
  <p>
    But this is easy to resolve.
    We can require the input range to be <code>borrowed_range</code> when the target object is a view.
    That is to say, even if the input range is destroyed after the function call,
    its iterator is still valid, thus there is no dangling. Noted that this particular requirement should not be a
    function signature but a <i>Mandates</i>,
    since we do not know the type of the input range for the <code>to(Args&&)</code> overload at this point,
    which would lead this overload to be called accidentally when calling
    <code>ranges::to&lt;string_view&gt;(<i>non-borrowed-range-types</i>)</code>.
  </p>
  <p>
    As a result, the requirements that the target type should not be <code>view</code> or the input type should be
    <code>borrowed_range</code>
    when the
    target type is <code>view</code> need be moved into <i>Mandates</i> of <code>to(R&&, Args&&...)</code>, which also
    resolves LWG <a href="https://cplusplus.github.io/LWG/issue3985">3985</a>.
  </p>
  <p>The following is the Tony table for the relaxation and I believes that this can be
    regarded as a DR for C++23.
  </p>
  <blockquote>
    <table border="1">
      <tr>
        <th>
          Before
        </th>
        <th>
          After P3544
        </th>
      </tr>
      <tr>
        <td>
<pre>

  auto sv1 = ranges::to&lt;string_view&gt;("abc"s );      // <span style="color:red;font-weight:bolder">error</span>  
  auto sv2 = ranges::to&lt;string_view&gt;("abc"sv);      // <span style="color:red;font-weight:bolder">error</span> 
  
  array arr{...};
  auto sp1 = ranges::to&lt;span&lt;int&gt;&gt;(std::move(arr)); // <span style="color:red;font-weight:bolder">error</span>
  auto sp2 = ranges::to&lt;span&lt;int&gt;&gt;(arr);            // <span style="color:red;font-weight:bolder">error</span> 

</pre>
        </td>
        <td>
          <pre>

  auto sv1 = ranges::to&lt;string_view&gt;("abc"s );      // <span style="color:red;font-weight:bolder">error</span>  
  auto sv2 = ranges::to&lt;string_view&gt;("abc"sv);      // <span style="color:#00A000;font-weight:bolder">ok</span> 

  array arr{...};
  auto sp1 = ranges::to&lt;span&lt;int&gt;&gt;(std::move(arr)); // <span style="color:red;font-weight:bolder">error</span>
  auto sp2 = ranges::to&lt;span&lt;int&gt;&gt;(arr);            // <span style="color:#00A000;font-weight:bolder">ok</span> 

</pre>
        </td>
      </tr>
      <tr>
        <td>
<pre>

  auto take = views::iota(0)
            | ranges::to&lt;ranges::take_view&gt;(5);     // <span style="color:red;font-weight:bolder">error</span>  
  
  auto drop = vector&lt;int&gt;{...}
            | ranges::to&lt;ranges::drop_view&gt;(5);     // <span style="color:red;font-weight:bolder">error</span> 

</pre>
        </td>
        <td>
          <pre>

  auto take = views::iota(0)
            | ranges::to&lt;ranges::take_view&gt;(5);     // <span style="color:#00A000;font-weight:bolder">ok, CTAD via ranges::to, but meh</span>  
  
  auto drop = vector&lt;int&gt;{...}
            | ranges::to&lt;ranges::drop_view&gt;(5);     // <span style="color:red;font-weight:bolder">error</span> 

</pre>
        </td>
      </tr>
      <tr>
        <td>
          <pre>

  auto ints = "1.2.3.4"sv  
            | views::split('.')
            | ranges::to&lt;vector&lt;string_view&gt;&gt;();    // <span style="color:red;font-weight:bolder">error</span> 
         
</pre>

        </td>

        <td>
          <pre>

  auto ints = "1.2.3.4"sv  
            | views::split('.')
            | ranges::to&lt;vector&lt;string_view&gt;&gt;();    // <span style="color:#00A000;font-weight:bolder">ok</span> 
          
        </pre>

        </td>
      </tr>
      <tr>
        <td>
          <pre>

  int numbers[] = {...};
  auto groups1 = numbers 
               | views::slide(3)
               | ranges::to&lt;vector&lt;span&lt;int&gt;&gt;&gt;();    // <span style="color:#00A000;font-weight:bolder">ok</span>
  auto groups2 = numbers 
               | views::slide(3)
               | ranges::to&lt;vector&lt;span&lt;int, 3&gt;&gt;&gt;(); // <span style="color:red;font-weight:bolder">error</span>

</pre>
        </td>
        <td>
          <pre>

  int numbers[] = {...};
  auto groups1 = numbers 
               | views::slide(3)
               | ranges::to&lt;vector&lt;span&lt;int&gt;&gt;&gt;();    // <span style="color:#00A000;font-weight:bolder">ok</span>
  auto groups2 = numbers 
               | views::slide(3)
               | ranges::to&lt;vector&lt;span&lt;int, 3&gt;&gt;&gt;(); // <span style="color:#00A000;font-weight:bolder">ok, recursively via ranges::to</span>  
            
</pre>
        </td>
      </tr>
      <tr>
        <td>
          <pre>

  auto views = vector&lt;int&gt;{...}
             | views::transform([](int x) { return to_string(x); })
             | ranges::to&lt;vector&lt;string_view&gt;&gt;();    // <span style="color:#00A000;font-weight:bolder">ok, but dangling</span>  

</pre>
        </td>
        <td>
          <pre>

  auto views = vector&lt;int&gt;{...}
             | views::transform([](int x) { return to_string(x); })
             | ranges::to&lt;vector&lt;string_view&gt;&gt;();    // <span style="color:#00A000;font-weight:bolder">ok, but dangling</span>  
        
</pre>
        </td>
      </tr>

    </table>
  </blockquote>
  </ol>
  <a name="Proposed-change"></a>
  <h2>Proposed change</h2>
  <p>This wording is relative to <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/n5001.pdf">N5001</a>.
  <ol>
    <li>
      <p>Modify 25.2 <a href="https://wg21.link/ranges.syn">[ranges.syn]</a> as indicated:</p>

      <blockquote>
        <pre>
#include &lt;compare&gt;              // <i>see <a href="https://wg21.link/compare.syn">[compare.syn]</a></i>
#include &lt;initializer_list&gt;     // <i>see <a href="https://wg21.link/initializer.list.syn">[initializer.list.syn]</a></i>
#include &lt;iterator&gt;             // <i>see <a href="https://wg21.link/iterator.synopsis">[iterator.synopsis]</a></i>

namespace std::ranges {
  […]
  // <i><a href="https://wg21.link/range.utility.conv">[range.utility.conv]</a>, range conversions</i>
  template&lt;class C, input_range R, class... Args&gt; <del>requires (!view&lt;C&gt;)</del>
    constexpr C to(R&amp;&amp; r, Args&amp;&amp;... args);                                          // <i>freestanding</i>
  template&lt;template&lt;class...&gt; class C, input_range R, class... Args&gt;
    constexpr auto to(R&amp;&amp; r, Args&amp;&amp;... args);                                       // <i>freestanding</i>
  template&lt;class C, class... Args&gt; <del>requires (!view&lt;C&gt;)</del>
    constexpr auto to(Args&amp;&amp;... args);                                              // <i>freestanding</i>
  template&lt;template&lt;class...&gt; class C, class... Args&gt;
    constexpr auto to(Args&amp;&amp;... args);                                              // <i>freestanding</i>
  […]
}
</pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 25.5.7.2 <a href="https://wg21.link/range.utility.conv.to">[range.utility.conv.to]</a> as indicated:
      </p>
      <blockquote>
        <pre>template&lt;class C, input_range R, class... Args&gt; <del>requires (!view&lt;C&gt;)</del>
constexpr C to(R&amp;&amp; r, Args&amp;&amp;... args);
</pre>
        <blockquote>
          <p>
            -1- <i>Mandates</i>:
          <ol style="list-style-type: none">
            <li>
              <p>(2.1) &mdash; <tt>C</tt> is a cv-unqualified class type.</p>
            </li>
            <li>
              <p><ins>(?.?) &mdash; <tt>C</tt> does not satisfy <code>view</code> or <code>R</code> models
                  <code>borrowed_range</code>.</ins></p>
            </li>
          </ol>
          </p>
    </li>
    <li>
      <p>Modify 25.5.7.3 <a href="https://wg21.link/range.utility.conv.adaptors">[range.utility.conv.adaptors]</a> as
        indicated:</p>
      <blockquote>
        <pre>template&lt;class C, class... Args&gt; <del>requires (!view&lt;C&gt;)</del>
  constexpr auto to(Args&amp;&amp;... args);
template&lt;template&lt;class...&gt; class C, class... Args&gt;
  constexpr auto to(Args&amp;&amp;... args);
</pre>
      </blockquote>
    </li>
  </ol>
  </blockquote>
  </li>
  </ol>
  </ol>
  </div>

</html>