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

### 3286. `ranges::size` is not required to be valid after a call to `ranges::begin` on an input range

Section: 26.7.10.2 [range.take.view], 26.5.4.2 [range.subrange.ctor] Status: C++20 Submitter: Eric Niebler Opened: 2019-09-10 Last modified: 2021-02-25

Priority: 0

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

View all issues with C++20 status.

Discussion:

On an input (but not forward) range, `begin(rng)` is not required to be an equality-preserving expression (26.4.2 [range.range]/3.3). If the range is also sized, then it is not valid to call `size(rng)` after `begin(rng)` (26.4.3 [range.sized]/2.2). In several places in the ranges clause, this precondition is violated. A trivial re-expression of the effects clause fixes the problem.

[2019-10-12 Issue Prioritization]

Status to Tentatively Ready and priority to 0 after seven positive votes on the reflector.

Proposed resolution:

This wording is relative to N4830.

1. Modify 26.7.10.2 [range.take.view], class template `take_view` synopsis, as indicated:

   >     namespace std::ranges {
   >       template<view V>
   >       class take_view : public view_interface<take_view<V>> {
   >       private:
   >         […]
   >       public:
   >         […]
   >         constexpr auto begin() requires (!simple-view<V>) {
   >           if constexpr (sized_range<V>) {
   >             if constexpr (random_access_range<V>)
   >               return ranges::begin(base_);
   >             else {
   >               auto sz = size();
   >               return counted_iterator{ranges::begin(base_), size()sz};
   >             }
   >           } else
   >             return counted_iterator{ranges::begin(base_), count_};
   >         }

   >         constexpr auto begin() const requires range<const V> {
   >           if constexpr (sized_range<const V>) {
   >             if constexpr (random_access_range<const V>)
   >               return ranges::begin(base_);
   >             else {
   >               auto sz = size();
   >               return counted_iterator{ranges::begin(base_), size()sz};
   >             }
   >           } else
   >             return counted_iterator{ranges::begin(base_), count_};
   >         }

   >         […]
   >       };
   >       […]
   >     }

2. Modify 26.5.4.2 [range.subrange.ctor] as indicated:

   >     template<not-same-as<subrange> R>
   >       requires forwarding-range<R> &&
   >         convertible_to<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S>
   >     constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);

   > > -6- Effects: Equivalent to:

   > > 1. (6.1) — If `StoreSize` is `true`, `subrange{ranges::begin(r), ranges::end(r)r, ranges::size(r)}`.

   > > 2. (6.2) — Otherwise, `subrange{ranges::begin(r), ranges::end(r)}`.