view_interface::back
is overconstrainedSection: 25.5.3 [view.interface] Status: Tentatively NAD Submitter: Hewill Kang Opened: 2023-10-28 Last modified: 2024-06-24
Priority: Not Prioritized
View all other issues in [view.interface].
View all issues with Tentatively NAD status.
Discussion:
Currently, view_interface
only provides the back
member when the derived class satisfies both
bidirectional_range
and common_range
, which ensures that ranges::prev
can act its sentinel.
common_range
seems to be too strict because when the derived class satisfies both
random_access_range
and sized_range
, its end iterator can still be calculated in constant time,
which is what some range adaptors currently do to greedily become common ranges.
I think we should follow similar rules to eliminate this inconsistency (demo):
#include <ranges>
constexpr auto r = std::ranges::subrange(std::views::iota(0), 5);
constexpr auto z = std::views::zip(r);
static_assert(r.back() == 4); // ill-formed
static_assert(std::get<0>(z.back()) == 4); // ok
[2023-11-07; Reflector poll]
NAD. "During the concat
discussion LEWG decided not to
support the corner case of random-access sized but not-common ranges."
"If we did want to address such ranges, would be better to enforce commonness
for random-access sized ranges by having ranges::end
return
ranges::begin(r) + ranges::size(r)
."
Proposed resolution:
This wording is relative to N4964.
Modify 25.5.3 [view.interface], class template view_interface
synopsis, as indicated:
namespace std::ranges { template<class D> requires is_class_v<D> && same_as<D, remove_cv_t<D>> class view_interface { […] public: […] constexpr decltype(auto) back() requires (bidirectional_range<D> && common_range<D>) || (random_access_range<D> && sized_range<D>); constexpr decltype(auto) back() const requires (bidirectional_range<const D> && common_range<const D>) || (random_access_range<const D> && sized_range<const D>); […] }; }
Modify 25.5.3.2 [view.interface.members] as indicated:
constexpr decltype(auto) back() requires (bidirectional_range<D> && common_range<D>) || (random_access_range<D> && sized_range<D>); constexpr decltype(auto) back() const requires (bidirectional_range<const D> && common_range<const D>) || (random_access_range<const D> && sized_range<const D>);-3- Preconditions:
-4- Effects: Equivalent to:!empty()
istrue
.auto common-arg-end = []<class R>(R& r) { if constexpr (common_range<R>) { return ranges::end(r); } else { return ranges::begin(r) + ranges::distance(r); } }; return *ranges::prev(common-arg-endranges::end(derived()));