reverse_view<V>
unintentionally requires range<const V>
Section: 25.7.21.2 [range.reverse.view] Status: C++20 Submitter: Patrick Palka Opened: 2020-02-04 Last modified: 2021-02-25
Priority: 0
View all other issues in [range.reverse.view].
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.
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.
Modify 25.7.21.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(); constexprreverse_iterator<iterator_t<const V>>auto end() const requires common_range<const V>; […] }; […] }constexpr reverse_iterator<iterator_t<V>> begin() requires common_range<V>; constexprreverse_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(); constexprreverse_iterator<iterator_t<const V>>auto end() const requires common_range<const V>;-6- Effects: Equivalent to:
return make_reverse_iterator(ranges::begin(base_));