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.

### 3523. `iota_view::sentinel` is not always `iota_view`'s sentinel

Section: 26.6.4.2 [range.iota.view] Status: WP Submitter: Tim Song Opened: 2021-02-17 Last modified: 2021-06-07

Priority: Not Prioritized

View all other issues in [range.iota.view].

View all issues with WP status.

Discussion:

P1739R4 added the following constructor to `iota_view`:

>     constexpr iota_view(iterator first, sentinel last) : iota_view(*first, last.bound_) {}

However, while `iota_view`'s iterator type is always `iota_view::iterator`, its sentinel type is not always `iota_view::sentinel`. First, if `Bound` is `unreachable_sentinel_t`, then the sentinel type is `unreachable_sentinel_t` too - we don't add an unnecessary level of wrapping on top. Second, when `W` and `Bound` are the same type, `iota_view` models `common_range`, and the sentinel type is the same as the iterator type - that is, `iterator`, not `sentinel`.

Presumably the intent is to use the view's actual sentinel type, rather than always use the `sentinel` type.

[2021-03-12; Reflector poll]

Set status to Tentatively Ready after five votes in favour during reflector poll.

[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4878.

1. Edit 26.6.4.2 [range.iota.view], as indicated:

   >     namespace std::ranges {
   >       // [...]

   >       template<weakly_incrementable W, semiregular Bound = unreachable_sentinel_t>
   >         requires weakly-equality-comparable-with<W, Bound> && semiregular<W>
   >       class iota_view : public view_interface<iota_view<W, Bound>> {
   >       private:
   >         // [range.iota.iterator], class iota_view​::​iterator
   >         struct iterator;            // exposition only
   >         // [range.iota.sentinel], class iota_view​::​sentinel
   >         struct sentinel;            // exposition only
   >         W value_ = W();             // exposition only
   >         Bound bound_ = Bound();     // exposition only
   >       public:
   >         iota_view() = default;
   >         constexpr explicit iota_view(W value);
   >         constexpr iota_view(type_identity_t<W> value,
   >                             type_identity_t<Bound> bound);
   >         constexpr iota_view(iterator first, sentinelsee below last);: iota_view(*first, last.bound_) {}

   >         constexpr iterator begin() const;
   >         constexpr auto end() const;
   >         constexpr iterator end() const requires same_as<W, Bound>;

   >         constexpr auto size() const requires see below;
   >       };

   >       template<class W, class Bound>
   >           requires (!is-integer-like<W> || !is-integer-like<Bound> ||
   >                   (is-signed-integer-like<W> == is-signed-integer-like<Bound>))
   >           iota_view(W, Bound) -> iota_view<W, Bound>;
   >     }

   > [...]

   >     constexpr iota_view(type_identity_t<W> value, type_identity_t<Bound> bound);

   > > -8- Preconditions: `Bound` denotes `unreachable_sentinel_t` or `bound` is reachable from `value`. When `W` and `Bound` model `totally_ordered_with`, then `bool(value <= bound)` is true.

   > > -9- Effects: Initializes `value_` with `value` and `bound_` with `bound`.

   >     constexpr iota_view(iterator first, see below last);

   > > -?- Effects: Equivalent to:

   > > 1. (?.1) — If `same_as<W, Bound>` is `true`, `iota_view(first.value_, last.value_)`.

   > > 2. (?.2) — Otherwise, if `Bound` denotes `unreachable_sentinel_t`, `iota_view(first.value_, last)`.

   > > 3. (?.3) — Otherwise, `iota_view(first.value_, last.bound_)`.

   > > -?- Remarks: The type of `last` is:

   > > 1. (?.1) — If `same_as<W, Bound>` is `true`, `iterator`.

   > > 2. (?.2) — Otherwise, if `Bound` denotes `unreachable_sentinel_t`, `Bound`.

   > > 3. (?.3) — Otherwise, `sentinel`.