<html>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Making user-defined constructors of view iterators/sentinels private</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>P3059R1</td>
      </tr>
      <tr>
        <td>Date</td>
        <td>2024-05-15</td>
      </tr>
      <tr>
        <td>Audience</td>
        <td>LEWG
        </td>
      </tr>
      <tr>
        <td>Reply-to</td>
        <td>Hewill Kang &lt;hewillk@gmail.com&gt;</td>
      </tr>
    </tbody>
  </table>
  <hr>
  <h1>Making user-defined constructors of view iterators/sentinels private</h1>
  <ul>
    <li>
      <ul>
        <li>Abstract</li>
        <li>Revision history</li>
        <li>Discussion</li>
        <li>Proposed change</li>
      </ul>
    </li>
  </ul>
  <a name="Abstract"></a>
  <h2>Abstract</h2>
  <p>
    The exposure of user-defined constructors for iterators/sentinels in <code>&lt;ranges&gt;</code> currently does not
    follow consistent rules, which is reflected in the fact that some of them are public and some are private.
    This paper disables their visibility to comply with best practices.</p>
  <p>Note that this may be a potential break, but after consulting the opinions of the various library implementers,
    this break is extremely unlikely. If so, it mostly indicates a user bug.</p>
  <a name="Revision history"></a>
  <h2>Revision history</h2>
  <p>
  <h3>R1</h3>
  <p>Added discussion for breakage.</p>
  <h3>R0</h3>
  <p>Initial revision.</p>
  </p>
  <a name="Discussion"></a>
  <h2>Discussion</h2>
  <p>
  <h3>What's the issue?</h3>
  <p>
    Currently in <code>&lt;ranges&gt;</code>, to access the <code><i>meow</i>_view</code>'s member variables,
    <code><i>meow</i>_view::<i>iterator</i></code>/<code><i>sentinel</i></code> saves a pointer pointing to
    <code><i>meow</i>_view</code>
    and provides a constructor that accepts a reference to it for initializing the pointer.
  </p>
  <p>
    However, some of these user-defined constructors are declared as <code>public</code>, which allows users to
    construct them by passing in a specific view base:
  </p>
  <pre>
    auto base = std::views::iota(0);
    auto filter = base | std::views::filter([](int) { return true; });
    auto begin = decltype(filter.begin())(filter, base.begin()); // ok
    auto end   = decltype(filter.end()  )(filter);               // ok
  </pre>
  <p>
    The author believes that we should prohibit providing these constructors to users.
    As the example above shows, this doesn't make much sense and provides no observable value.
  </p>
  <p>
    It is worth noting that the above example fails to compile in libstdc++, because in libstdc++ the constructor is
    implemented to accept a pointer to <code>filter_view</code>,
    which allows it to directly pass in <code>this</code> pointer in <code>begin()</code> to save one
    <code>addressof</code> call.
  </p>
  <p>
    Although this is a bug in libstdc++ according to the current wording, it is clearly a side effect of the constructor
    being accidentally exposed.
    Implementers are absolutely allowed to construct the iterator by just passing <code>this</code> to initialize the
    member, which is what <code>chunk_view::<i>iterator</i></code>'s user-defined constructor does.
  </p>
  <p>
    Since both methods exist in <code>&lt;ranges&gt;</code>, it shows that this is implementation-related and should not
    be perceived by users.
  </p>
  <p>
    The author believes that apart from the default constructor and the conversion constructor which has an obvious
    intent, there is no reason for constructors that are only used for implementation purposes to be exposed to the
    user.
  </p>
  <h3>What are the potential breakages?</h3>
  <p>During the Tokyo meeting, SG9 was concerned about the potential breakage that would result from declaring these
    constructors <tt>private</tt>. However, the actual damage caused by such change is negligible.</p>
  <p>For libstdc++, to work around the issue that instantiating the <tt>begin()</tt>/<tt>end()</tt>
    requires computing the satisfaction of the <tt>range</tt> concept, <a
      href="https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=afb8da7faa9dfe5a0d94ed45a373d74c076784ab">r11-4584</a>
    changes several user-defined constructors mentioned in the paper from taking a reference to taking a pointer,
    indicating no breakages for GCC users in this paper because those constructors
    do not exist in the first place.
    Although later <a
      href="https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=9324f7a25c7161a813bfae6cc2d180784b165740">r11-5954</a>
    optimized the frontend making the former workaround redundant, rechanging these constructors to take a reference
    to conform to the current wording seems to be a bad idea, since no user is actually using them.</p>
  </p>
  <p>MSVC-STL doesn't seem to have much concern about this either. In the SG9 mailing list, Mr. Stephan believes
    that the paper has made a great change and expressed strong support for the direction.</p>
  <p>Although libc++ has a <a
    href="https://github.com/llvm/llvm-project/blob/main/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp">test</a> specifically for the user-defined constructor of
    <code>basic_istream_view::<i>iterator</i></code>, Mr. Louis acknowledged that this was simply a matter of maximizing coverage, and
    he thinks that it is no big deal to turn these constructors into <tt>private</tt>. Quoted from the
    SG9 mailing list: "<i>I'd be surprised if we found any breakage, and if we did I wouldn't be surprised if there was
      something wrong with that code in the first place.</i>"
  </p>
  <p>
    In summary, the potential breakages do not cause any concern for the implementers of three major standard libraries.
    The author believes that this paper highlights the better design direction of C++23 range adaptors. It is worthwhile
    to bring these changes back to C++20 ranges adaptors, just as we did in <a
      href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2711r1.html">P2711</a>: <i>Making multi-param
      constructors of views <code>explicit</code></i>.
  </p>
  <a name="Proposed-change"></a>
  <h2>Proposed change</h2>
  <p>
    This wording is relative to <a href="https://wg21.link/N4958">N4958</a>.
  </p>
  <blockquote class="note">
    <p>
      [<i>Drafting note</i>: The proposed resolution does not touch user-defined constructors of
      <tt>iota_view::<i>iterator</i></tt>/<tt><i>sentinel</i></tt> because it does make sense to expose them.]
    </p>
  </blockquote>
  <ol>
    <li>
      <p>Modify 26.6.6.3 <a href="https://wg21.link/range.istream.iterator">[range.istream.iterator]</a>, class
        <tt>basic_istream_view::<i>iterator</i></tt> synopsis, as indicated:
      </p>

      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;movable Val, class CharT, class Traits&gt;
        requires default_initializable&lt;Val&gt; &amp;&amp;
                 <i>stream-extractable</i>&lt;Val, CharT, Traits&gt;
      class basic_istream_view&lt;Val, CharT, Traits&gt;::<i>iterator</i> {
      public:
        using iterator_concept = input_iterator_tag;
        using difference_type = ptrdiff_t;
        using value_type = Val;
    
        <del>constexpr explicit <i>iterator</i>(basic_istream_view&amp; parent) noexcept;</del>
    
        [&hellip;]
      
      private:  
        basic_istream_view* <i>parent_</i>;                                        // <i>exposition only</i>
    
        <ins>constexpr explicit <i>iterator</i>(basic_istream_view&amp; parent) noexcept;   // <i>exposition only</i></ins>
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.8.3 <a href="https://wg21.link/range.filter.iterator">[range.filter.iterator]</a>, class
        <tt>filter_view::<i>iterator</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, indirect_unary_predicate&lt;iterator_t&lt;V&gt;&gt; Pred&gt;
        requires view&lt;V&gt; &amp;&amp; is_object_v&lt;Pred&gt;
      class filter_view&lt;V, Pred&gt;::<i>iterator</i> {
      private:
        iterator_t&lt;V&gt; <i>current_</i> = iterator_t&lt;V&gt;();   // <i>exposition only</i>
        filter_view* <i>parent_</i> = nullptr;             // <i>exposition only</i>
    
        <ins>constexpr <i>iterator</i>(filter_view&amp; parent, iterator_t&lt;V&gt; current);   // <i>exposition only</i></ins>
    
      public:
        [&hellip;]
    
        <i>iterator</i>() requires default_initializable&lt;iterator_t&lt;V&gt;&gt; = default;
        <del>constexpr <i>iterator</i>(filter_view&amp; parent, iterator_t&lt;V&gt; current);</del>
    
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.8.4 <a href="https://wg21.link/range.filter.sentinel">[range.filter.sentinel]</a>, class
        <tt>filter_view::<i>sentinel</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, indirect_unary_predicate&lt;iterator_t&lt;V&gt;&gt; Pred&gt;
        requires view&lt;V&gt; &amp;&amp; is_object_v&lt;Pred&gt;
      class filter_view&lt;V, Pred&gt;::<i>sentinel</i> {
      private:
        sentinel_t&lt;V&gt; <i>end_</i> = sentinel_t&lt;V&gt;();       // <i>exposition only</i>
    
        <ins>constexpr explicit <i>sentinel</i>(filter_view&amp; parent);   // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(filter_view&amp; parent);</del>
    
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.9.3 <a href="https://wg21.link/range.transform.iterator">[range.transform.iterator]</a>, class
        template <tt>transform_view::<i>iterator</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, move_constructible F&gt;
        requires view&lt;V&gt; &amp;&amp; is_object_v&lt;F&gt; &amp;&amp;
                 regular_invocable&lt;F&amp;, range_reference_t&lt;V&gt;&gt; &amp;&amp;
                 <i>can-reference</i>&lt;invoke_result_t&lt;F&amp;, range_reference_t&lt;V&gt;&gt;&gt;
      template&lt;bool Const&gt;
      class transform_view&lt;V, F&gt;::<i>iterator</i> {
      private:
        [&hellip;]
    
        <ins>constexpr <i>iterator</i>(Parent&amp; parent, iterator_t&lt;<i>Base</i>&gt; current);  // <i>exposition only</i></ins>
    
      public:
        [&hellip;]
    
        <i>iterator</i>() requires default_initializable&lt;iterator_t&lt;Base&gt;&gt; = default;
        <del>constexpr <i>iterator</i>(Parent&amp; parent, iterator_t&lt;<i>Base</i>&gt; current);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.9.4 <a href="https://wg21.link/range.transform.sentinel">[range.transform.sentinel]</a>, class
        template <tt>transform_view::<i>sentinel</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, move_constructible F&gt;
        requires view&lt;V&gt; &amp;&amp; is_object_v&lt;F&gt; &amp;&amp;
                  regular_invocable&lt;F&amp;, range_reference_t&lt;V&gt;&gt; &amp;&amp;
                  <i>can-reference</i>&lt;invoke_result_t&lt;F&amp;, range_reference_t&lt;V&gt;&gt;&gt;
      template&lt;bool Const&gt;
      class transform_view&lt;V, F&gt;::<i>sentinel</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.10.3 <a href="https://wg21.link/range.take.sentinel">[range.take.sentinel]</a>, class template
        <tt>take_view::<i>sentinel</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;view V&gt;
      template&lt;bool Const&gt;
      class take_view&lt;V&gt;::<i>sentinel</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.11.3 <a href="https://wg21.link/range.take.while.sentinel">[range.take.while.sentinel]</a>, class
        template <tt>take_while_view::<i>sentinel</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;view V, class Pred&gt;
        requires input_range&lt;V&gt; && is_object_v&lt;Pred&gt; &amp;&amp;
                 indirect_unary_predicate&lt;const Pred, iterator_t&lt;V&gt;&gt;
      template&lt;bool Const&gt;
      class take_while_view&lt;V, Pred&gt;::<i>sentinel</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end, const Pred* pred);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end, const Pred* pred);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.14.4 <a href="https://wg21.link/range.join.sentinel">[range.join.sentinel]</a>, class template
        <tt>join_view::<i>sentinel</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V&gt;
        requires view&lt;V&gt; &amp;&amp; input_range&lt;range_reference_t&lt;V&gt;&gt;
      template&lt;bool Const&gt;
      struct join_view&lt;V&gt;::<i>sentinel</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>sentinel</i>(<i>Parent</i>&amp; parent);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
    
        <del>constexpr explicit <i>sentinel</i>(<i>Parent</i>&amp; parent);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.16.3 <a href="https://wg21.link/range.lazy.split.outer">[range.lazy.split.outer]</a>, class
        template <tt>lazy_split_view::<i>outer-iterator</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, forward_range Pattern&gt;
        requires view&lt;V&gt; &amp;&amp; view&lt;Pattern&gt; &amp;&amp;
                 indirectly_comparable&lt;iterator_t&lt;V&gt;, iterator_t&lt;Pattern&gt;, ranges::equal_to&gt; &amp;&amp;
                 (forward_range&lt;V&gt; || <i>tiny-range</i>&lt;Pattern&gt;)
      template&lt;bool Const&gt;
      struct lazy_split_view&lt;V, Pattern&gt;::<i>outer-iterator</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>outer-iterator</i>(Parent&amp; parent)                     // <i>exposition only</i>
          requires (!forward_range&lt;<i>Base</i>&gt;);
        constexpr <i>outer-iterator</i>(Parent& parent, iterator_t&lt;<i>Base</i>&gt; current)    // <i>exposition only</i>
          requires forward_range&lt;<i>Base</i>&gt;;</ins>
    
      public:
        [&hellip;]
        <del>constexpr explicit <i>outer-iterator</i>(Parent&amp; parent)
          requires (!forward_range&lt;<i>Base</i>&gt;);
        constexpr <i>outer-iterator</i>(Parent& parent, iterator_t&lt;<i>Base</i>&gt; current)
          requires forward_range&lt;<i>Base</i>&gt;;</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.16.5 <a href="https://wg21.link/range.lazy.split.inner">[range.lazy.split.inner]</a>, class
        template <tt>lazy_split_view::<i>inner-iterator</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, forward_range Pattern&gt;
        requires view&lt;V&gt; &amp;&amp; view&lt;Pattern&gt; &amp;&amp;
                  indirectly_comparable&lt;iterator_t&lt;V&gt;, iterator_t&lt;Pattern&gt;, ranges::equal_to&gt; &amp;&amp;
                  (forward_range&lt;V&gt; || <i>tiny-range</i>&lt;Pattern&gt;)
      template&lt;bool Const&gt;
      struct lazy_split_view&lt;V, Pattern&gt;::<i>inner-iterator</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>inner-iterator</i>(<i>outer-iterator</i>&lt;<i>Const</i>&gt; i);    // <i>exposition only</i></ins>
    
      public:
        [&hellip;]
    
        <i>inner-iterator</i>() = default;
        <del>constexpr explicit <i>inner-iterator</i>(<i>outer-iterator</i>&lt;<i>Const</i>&gt; i);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.17.3 <a href="https://wg21.link/range.split.iterator">[range.split.iterator]</a>, class
        <tt>split_view::<i>iterator</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;forward_range V, forward_range Pattern&gt;
        requires view&lt;V&gt; &amp;&amp; view&lt;Pattern&gt; &amp;&amp;
                 indirectly_comparable&lt;iterator_t&lt;V&gt;, iterator_t&lt;Pattern&gt;, ranges::equal_to&gt;
      class split_view&lt;V, Pattern&gt;::<i>iterator</i> {
      private:
        [&hellip;]
    
        <ins>constexpr <i>iterator</i>(split_view&amp; parent, iterator_t&lt;V&gt; current, subrange&lt;iterator_t&lt;V&gt;&gt; next);    // <i>exposition only</i></ins>
    
      public:
        [&hellip;]
    
        <i>iterator</i>() = default;
        <del>constexpr <i>iterator</i>(split_view&amp; parent, iterator_t&lt;V&gt; current, subrange&lt;iterator_t&lt;V&gt;&gt; next);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.17.4 <a href="https://wg21.link/range.split.sentinel">[range.split.sentinel]</a>, class
        <tt>split_view::<i>sentinel</i></tt> synopsis, as indicated:
      </p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;forward_range V, forward_range Pattern&gt;
        requires view&lt;V&gt; &amp;&amp; view&lt;Pattern&gt; &amp;&amp;
                 indirectly_comparable&lt;iterator_t&lt;V&gt;, iterator_t&lt;Pattern&gt;, ranges::equal_to&gt;
      struct split_view&lt;V, Pattern&gt;::<i>sentinel</i> {
      private:
        sentinel_t&lt;V&gt; <i>end_</i> = sentinel_t&lt;V&gt;();               // <i>exposition only</i>
    
        <ins>constexpr explicit <i>sentinel</i>(split_view&amp; parent);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(split_view&amp; parent);</del>
        [&hellip;]
      };
    }
      </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.22.3 <a href="https://wg21.link/range.elements.iterator">[range.elements.iterator]</a>, class
        template <tt>elements_view::<i>iterator</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, size_t N&gt;
        requires view&lt;V&gt; &amp;&amp; <i>has-tuple-element</i>&lt;range_value_t&lt;V&gt;, N&gt; &amp;&amp;
                 <i>has-tuple-element</i>&lt;remove_reference_t&lt;range_reference_t&lt;V&gt;&gt;, N&gt; &amp;&amp;
                 <i>returnable-element</i>&lt;range_reference_t&lt;V&gt;, N&gt;
      template&lt;bool Const&gt;
      class elements_view&lt;V, N&gt;::<i>iterator</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>iterator</i>(iterator_t&lt;<i>Base</i>&gt; current);    // <i>exposition only</i></ins>
    
      public:
        [&hellip;]
    
        <i>iterator</i>() requires default_initializable&lt;iterator_t&lt;<i>Base</i>&gt;&gt; = default;
        <del>constexpr explicit <i>iterator</i>(iterator_t&lt;<i>Base</i>&gt; current);</del>
        [&hellip;]
      };
    }
    </pre>
      </blockquote>
    </li>
    <li>
      <p>Modify 26.7.22.4 <a href="https://wg21.link/range.elements.sentinel">[range.elements.sentinel]</a>, class
        template <tt>elements_view::<i>sentinel</i></tt> synopsis, as indicated:</p>
      <blockquote>
        <pre>
    namespace std::ranges {
      template&lt;input_range V, size_t N&gt;
        requires view&lt;V&gt; &amp;&amp; <i>has-tuple-element</i>&lt;range_value_t&lt;V&gt;, N&gt; &amp;&amp;
                  <i>has-tuple-element</i>&lt;remove_reference_t&lt;range_reference_t&lt;V&gt;&gt;, N&gt; &amp;&amp;
                  <i>returnable-element</i>&lt;range_reference_t&lt;V&gt;, N&gt;
      template&lt;bool Const&gt;
      class elements_view&lt;V, N&gt;::<i>sentinel</i> {
      private:
        [&hellip;]
    
        <ins>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);    // <i>exposition only</i></ins>
    
      public:
        <i>sentinel</i>() = default;
        <del>constexpr explicit <i>sentinel</i>(sentinel_t&lt;<i>Base</i>&gt; end);</del>
        [&hellip;]
      };
    }
      </pre>
      </blockquote>
    </li>
  </ol>
  </ol>
  </div>
</body>

</html>