Created on 2026-03-25.00:00:00 last changed 1 week ago
Proposed resolution:
This wording is relative to N5032.
Modify [ranges.syn], header <ranges> synopsis, as indicated:
// mostly freestanding #include <compare> // see [compare.syn] #include <initializer_list> // see [initializer.list.syn] #include <iterator> // see [iterator.synopsis] namespace std::ranges { […] template<class T> concept sized-random-access-range = see below; // exposition only template<class T> concept single-pass-range = see below; // exposition only […] }
Modify[range.refinements] as indicated:
-8- The exposition-only concept `sized-random-access-range` specifies the requirements of a `range` type that is sized and allows random access to its elements.
template<class T> concept sized-random-access-range = // exposition only random_access_range<T> && sized_range<T>;[Note 1: This concept constrains some parallel algorithm overloads; see [algorithms]. — end note]
-?- The exposition-only concept `single-pass-range` specifies the requirements of a `range` type that can only be traversed once and does not guarantee multi-pass safety.
[Drafting note: The `input_range` is not required in `single-pass-range` because views like `drop_view` can also apply on `output_range`.]template<class T> concept single-pass-range = // exposition only range<T> && !forward_range<T>;
Modify [range.filter.view] as indicated:
[Drafting note: This just reuse `single-pass-range` concept in `filter_view to reduce.]
namespace std::ranges {
template<input_range V, indirect_unary_predicate<iterator_t<V>> Pred>
requires view<V> && is_object_v<Pred>
class filter_view : public view_interface<filter_view<V, Pred>> {
[…]
constexpr iterator<true> begin() const
requires single-pass-range(input_range<const V> && !forward_range<const V> &&
indirect_unary_predicate<const Pred, iterator_t<const V>>);
[…]
constexpr sentinel<true> end() const
requires single-pass-range(input_range<const V> && !forward_range<const V> &&
indirect_unary_predicate<const Pred, iterator_t<const V>>) {
return sentinel<true>{*this};
}
[…]
};
[…]
}
[…]constexpr iterator<true> begin() const requires single-pass-range(input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>);-6-Preconditions:
pred_.has_value()istrue.
Modify [range.drop.view] as indicated:
[Drafting note:
This reuse exposition only sized-random-access-range,
which is defined in the same place as `single-pass-range`, to reduce typing.]
namespace std::ranges { template<view V> class drop_view : public view_interface<drop_view<V>> { public: […] constexpr auto begin() requires (!(simple-view<V> && (sized-random-access-range[…]random_access_range<const V> && sized_range<const V> || single-pass-range<const V>))); constexpr auto begin() const requires sized-random-access-rangerandom_access_range<const V> && sized_range<const V> || single-pass-range<const V>; […] }; […] }constexpr auto begin() requires (!(simple-view<V> && (sized-random-access-rangerandom_access_range<const V> && sized_range<const V> || single-pass-range<const V>))); constexpr auto begin() const requires sized-random-access-rangerandom_access_range<const V> && sized_range<const V> || single-pass-range<const V>;-3-Returns:
ranges::next(ranges::begin(base_), count_, ranges::end(base_)).-4-Remarks: In order to provide the amortized constant-time complexity required by the `range` concept when `drop_view` models `forward_range`, the first overload caches the result within the `drop_view` for use on subsequent calls.
Modify [range.drop.while.view] as indicated:
namespace std::ranges { template<view V, class Pred> requires input_range<V> && is_object_v<Pred> && indirect_unary_predicate<const Pred, iterator_t<V>> class drop_while_view : public view_interface<drop_while_view<V, Pred>> { public: […] constexpr auto begin() requires (!(simple-view<V> && single-pass-range<const V>)); constexpr auto begin() const requires single-pass-range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>; constexpr auto end() requires (!simple-view<V>) { return ranges::end(base_); } constexpr auto end() const requires range<const V> { return ranges::end(base_); } […] }; […] }[…]constexpr auto begin() requires (!(simple-view<V> && single-pass-range<const V>)); constexpr auto begin() const requires single-pass-range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>;-3-Preconditions:
pred_.has_value()istrue.-4-Returns:
ranges::find_if_not(base_, cref(*pred_)).-5-Remarks: In order to provide the amortized constant-time complexity required by the `range` concept when `drop_while_view` models `forward_range`, the first overload
callcaches the result within the `drop_while_view` for use on subsequent calls.
[ 2026-06-16; Hewill provides new wording ]
[ 2026-05-29 LWG reflector poll; status: New → LEWG ]
This wording is relative to N5032.
Modify [range.drop.view] as indicated:
namespace std::ranges { template<view V> class drop_view : public view_interface<drop_view<V>> { public: […] constexpr auto begin() requires (!(simple-view<V> && ((random_access_range<const V> && sized_range<const V>) || (input_range<const V> && !forward_range<const V>)))); constexpr auto begin() const requires (random_access_range<const V> && sized_range<const V>) || (input_range<const V> && !forward_range<const V>); […] }; […] }constexpr auto begin() requires (!(simple-view<V> && ((random_access_range<const V> && sized_range<const V>) || (input_range<const V> && !forward_range<const V>)))); constexpr auto begin() const requires (random_access_range<const V> && sized_range<const V>) || (input_range<const V> && !forward_range<const V>);-3- Returns:
-4- Remarks: In order to provide the amortized constant-time complexity required by theranges::next(ranges::begin(base_), count_, ranges::end(base_)).rangeconcept whendrop_viewmodelsforward_range, the first overload caches the result within thedrop_viewfor use on subsequent calls.
Modify [range.drop.while.view] as indicated:
[…]namespace std::ranges { template<view V, class Pred> requires input_range<V> && is_object_v<Pred> && indirect_unary_predicate<const Pred, iterator_t<V>> class drop_while_view : public view_interface<drop_while_view<V, Pred>> { public: […] constexpr auto begin() requires (!(simple-view<V> && input_range<const V> && !forward_range<const V>)); constexpr auto begin() const requires (input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>); constexpr auto end() requires (!simple-view<V>) { return ranges::end(base_); } constexpr auto end() const requires range<const V> { return ranges::end(base_); } […] }; […] }constexpr auto begin() requires (!(simple-view<V> && input_range<const V> && !forward_range<const V>)); constexpr auto begin() const requires (input_range<const V> && !forward_range<const V> && indirect_unary_predicate<const Pred, iterator_t<const V>>);-3-Preconditions:
-4-Returns:pred_.has_value()istrue.ranges::find_if_not(base_, cref(*pred_)). -5-Remarks: In order to provide the amortized constant-time complexity required by therangeconcept whendrop_while_viewmodelsforward_range, the first overloadcallcaches the result within thedrop_while_viewfor use on subsequent calls.
After P3725R3,
filter_view can be const-iterable as long as the underlying range is input-only range,
implying that LEWG do believe that providing const-iterable properties for views
does have some value.
drop_view and drop_while_view are also const-iterable in
the same situation, because they do not internally need to cache the begin call on the first
iteration.
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2026-06-16 15:03:28 | admin | set | messages: + msg16482 |
| 2026-05-30 15:28:42 | admin | set | messages: + msg16354 |
| 2026-05-30 15:28:42 | admin | set | status: new -> lewg |
| 2026-03-26 06:28:24 | admin | set | status: immediate -> new |
| 2026-03-25 16:28:14 | admin | set | messages: + msg16083 |
| 2026-03-25 00:00:00 | admin | create | |