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.

### 3387. §[range.reverse.view] `reverse_view<V>` unintentionally requires `range<const V>`

Section: 24.7.17.2 [range.reverse.view] Status: C++20 Submitter: Patrick Palka Opened: 2020-02-04 Last modified: 2021-02-25

Priority: 0

View all issues with C++20 status.

Discussion:

`reverse_view<V>` requires `bidirectional_range<V>`, but not `range<const V>`, which means that `iterator_t<const V>` might be an invalid type. The return types of the `begin() const` and `end() const` overloads make use of `iterator_t<const V>` in a non-SFINAE context, which means that instantiating `reverse_view<X>` is ill-formed unless `range<const X>` is satisfied.

Code like `x | views::filter(p) | views::reverse` fails to compile because `const filter_view<…>` does not model `range`, so `iterator_t<const filter_view<…>>` is invalid.

Either `range<const V>` needs to be in the class' `requires`-clause, or the return types of the `const`-qualified `begin()` and `end()` need to delay use of `iterator_t<const V>` until `range<const V>` is known to be satisfied.

Giving these overloads an `auto` return type means the type is determined when the member is called. The constraint `common_range<const V>` appropriately restricts the selection of these overloads, so they can only be called when the type is valid. This is what `cmcstl2` does. `range-v3` makes the `begin() const` and `end() const` members into function templates, so that they are SFINAE contexts. This is related to 3347.

[2020-02 Prioritized as IMMEDIATE Monday morning in Prague]

Proposed resolution:

This wording is relative to N4849.

1. Modify 24.7.17.2 [range.reverse.view] as indicated:

   > >     namespace std::ranges {
   > >       template<view V>
   > >         requires bidirectional_range<V>
   > >       class reverse_view : public view_interface<reverse_view<V>> {
   > >         […]
   > >         constexpr reverse_iterator<iterator_t<V>> begin();
   > >         constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
   > >         constexpr reverse_iterator<iterator_t<const V>>auto begin() const
   > >           requires common_range<const V>;

   > >         constexpr reverse_iterator<iterator_t<V>> end();
   > >         constexpr reverse_iterator<iterator_t<const V>>auto end() const
   > >           requires common_range<const V>;
   > >         […]
   > >       };
   > >       […]
   > >     }

   > > […]

   > >     constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>;
   > >     constexpr reverse_iterator<iterator_t<const V>>auto begin() const
   > >       requires common_range<const V>;

   > > > -5- Effects: Equivalent to: `return make_reverse_iterator(ranges::end(base_));`

   > >     constexpr reverse_iterator<iterator_t<V>> end();
   > >     constexpr reverse_iterator<iterator_t<const V>>auto end() const
   > >       requires common_range<const V>;

   > > > -6- Effects: Equivalent to: `return make_reverse_iterator(ranges::begin(base_));`