This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3449. `take_view` and `take_while_view`'s `sentinel<false>` not comparable with their const iterator

Section: 26.7.10.3 [range.take.sentinel], 26.7.11.3 [range.take.while.sentinel] Status: WP Submitter: Tim Song Opened: 2020-06-06 Last modified: 2020-11-09

Priority: 1

View all other issues in [range.take.sentinel].

View all issues with WP status.

Discussion:

During reflector discussion it was noted that the issue observed in LWG 3448 applies to `take_view::sentinel` and `take_while_view::sentinel` as well.

[2020-06-15 Tim corrects a typo in the PR]

[2020-10-02; Priority set to 1 in telecon]

Should be considered together with 3406 and 3448.

[2020-10-02; Status to Tentatively Ready after five positive votes on the reflector]

[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4861. It assumes the `maybe-const` helper introduced by the P/R of LWG 3448.

1. Modify 26.7.10.3 [range.take.sentinel] as indicated:

   > [Drafting note: Unlike LWG 3448, these operators can't be easily templatized, so the approach taken here is to add an overload for the opposite constness instead. However, because `const V` may not even be a range (and therefore `iterator_t<const V>` may not be well-formed), we need to defer instantiating the signature of the new overload until the point of use. ]

   > >     namespace std::ranges {
   > >       template<view V>
   > >       template<bool Const>
   > >       class take_view<V>::sentinel {
   > >       private:
   > >         using Base = conditional_t<Const, const V, V>;  // exposition only
   > >         template<bool OtherConst>
   > >         using CI = counted_iterator<iterator_t<Basemaybe-const<OtherConst, V>>>;  // exposition only

   > >         […]

   > >         constexpr sentinel_t<Base> base() const;

   > >         friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);

   > >         template<bool OtherConst = !Const>
   > >             requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
   > >         friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);

   > >       };
   > >     }

   > […]

   >     friend constexpr bool operator==(const CI<Const>& y, const sentinel& x);

   >     template<bool OtherConst = !Const>
   >         requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
   >     friend constexpr bool operator==(const CI<OtherConst>& y, const sentinel& x);

   > > -4- Effects: Equivalent to: `return y.count() == 0 || y.base() == x.end_;`

2. Modify 26.7.11.3 [range.take.while.sentinel] as indicated:

   > >     namespace std::ranges {
   > >         template<view V, class Pred>
   > >         requires input_range<V> && is_object_v<Pred> &&
   > >                     indirect_unary_predicate<const Pred, iterator_t<V>>
   > >         template<bool Const>
   > >         class take_while_view<V>::sentinel {
   > >           […]

   > >           constexpr sentinel_t<Base> base() const { return end_; }

   > >           friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);

   > >           template<bool OtherConst = !Const>
   > >               requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
   > >           friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& x, const sentinel& y);

   > >         };
   > >     }

   > […]

   >     friend constexpr bool operator==(const iterator_t<Base>& x, const sentinel& y);

   >     template<bool OtherConst = !Const>
   >         requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
   >     friend constexpr bool operator==(const iterator_t<maybe-const<OtherConst, V>>& x, const sentinel& y);

   > > -3- Effects: Equivalent to: `return y.end_ == x || !invoke(*y.pred_, *x);`