Title
§[range.reverse.view] reverse_view<V> unintentionally requires range<const V>
Status
c++20
Section
[range.reverse.view]
Submitter
Patrick Palka

Created on 2020-02-04.00:00:00 last changed 46 months ago

Messages

Date: 2020-02-10.19:13:13

Proposed resolution:

This wording is relative to N4849.

  1. Modify [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_));

Date: 2020-02-10.19:13:13

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

Date: 2020-02-10.19:13:13

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.
History
Date User Action Args
2021-02-25 10:48:01adminsetstatus: wp -> c++20
2020-02-24 16:02:59adminsetstatus: immediate -> wp
2020-02-10 19:13:13adminsetmessages: + msg11022
2020-02-10 19:13:13adminsetstatus: new -> immediate
2020-02-08 12:40:48adminsetmessages: + msg10992
2020-02-04 00:00:00admincreate