Created on 2025-07-28.00:00:00 last changed 1 month ago
Proposed resolution:
This wording is relative to N5014.
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 common-bidirectional-range = see below; // exposition only […] }
Modify [range.refinements] as indicated:
[…]-8- The exposition-only concept
sized-random-access-rangespecifies the requirements of arangetype 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 conceptcommon-bidirectional-rangespecifies the requirements of arangetype that is bidirectional and whose iterator and sentinel types are the same.template<class T> concept common-bidirectional-range = // exposition only bidirectional_range<T> && common_range<T>;
Modify [view.interface.general] as indicated:
-1- The class template
view_interfaceis a helper for defining view-like types that offer a container-like interface. It is parameterized with the type that is derived from it.namespace std::ranges { template<class D> requires is_class_v<D> && same_as<D, remove_cv_t<D>> class view_interface { private: […] public: […] constexpr decltype(auto) back() requiresbidirectional_range<D> && common_range<D>common-bidirectional-range<D>; constexpr decltype(auto) back() const requiresbidirectional_range<const D> && common_range<const D>common-bidirectional-range<const D>; […] }; }
Modify [view.interface.members] as indicated:
constexpr decltype(auto) back() requiresbidirectional_range<D> && common_range<D>common-bidirectional-range<D>; constexpr decltype(auto) back() const requiresbidirectional_range<const D> && common_range<const D>common-bidirectional-range<const D>;-3- Hardened preconditions:
-4- Effects: Equivalent to:!empty()istrue.return *ranges::prev(ranges::end(derived()));
Modify [range.take.overview] as indicated:
-2- The name
views::takedenotes a range adaptor object ([range.adaptor.object]). LetEandFbe expressions, letTberemove_cvref_t<decltype((E))>, and letDberange_difference_t<decltype((E))>. Ifdecltype((F))does not modelconvertible_to<D>,views::take(E, F)is ill-formed. Otherwise, the expressionviews::take(E, F)is expression-equivalent to:
- […]
(2.2) — Otherwise, if
[…]Tmodelsrandom_access_rangeandsized_rangesized-random-access-rangeand is a specialization ofspan([views.span]),basic_string_view([string.view]), orranges::subrange([range.subrange]), thenU(ranges::begin(E), ranges::begin(E) + std::min<D>(ranges::distance(E), F)), except thatEis evaluated only once, whereUis a type determined as follows:(2.3) — otherwise, if
Tis a specialization ofiota_view([range.iota.view]) that modelsrandom_access_rangeandsized_rangesized-random-access-range, theniota_view(*ranges::begin(E), *(ranges::begin(E) + std::min<D>(ranges::distance(E), F))), except thatEis evaluated only once.
Modify [range.drop.overview] as indicated:
-2- The name
views::dropdenotes a range adaptor object ([range.adaptor.object]). LetEandFbe expressions, letTberemove_cvref_t<decltype((E))>, and letDberange_difference_t<decltype((E))>. Ifdecltype((F))does not modelconvertible_to<D>,views::drop(E, F)is ill-formed. Otherwise, the expressionviews::drop(E, F)is expression-equivalent to:
- […]
(2.2) — Otherwise, if
[…]Tmodelsrandom_access_rangeandsized_rangesized-random-access-rangeand is(2.3) — Otherwise, if
Tis a specialization ofsubrange([range.subrange]) that modelsrandom_access_rangeandsized_rangesized-random-access-range, thenT(ranges::begin(E) + std::min<D>(ranges::distance(E), F), ranges::end(E), to-unsigned-like(ranges::distance(E) - std::min<D>(ranges::distance(E), F))), except thatEandFare each evaluated only once.
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>sized-random-access-range<const V>)); constexpr auto begin() const requiresrandom_access_range<const V> && sized_range<const V>sized-random-access-range<const V>; […] }; […] }constexpr auto begin() requires (!(simple-view<V> &&random_access_range<const V> && sized_range<const V>sized-random-access-range<const V>)); constexpr auto begin() const requiresrandom_access_range<const V> && sized_range<const V>sized-random-access-range<const V>;-3- Returns:
ranges::next(ranges::begin(base_), count_, ranges::end(base_)).
Modify [range.join.iterator] as indicated:
namespace std::ranges { template<input_range V> requires view<V> && input_range<range_reference_t<V>> template<bool Const> struct join_view<V>::iterator { private: […] public: […] constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>common-bidirectional-range<range_reference_t<Base>>; constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>common-bidirectional-range<range_reference_t<Base>>; […] }; }-1-
iterator::iterator_conceptis defined as follows::[…]
(1.1) — If
[…]ref-is-glvalueistrue,Basemodelsbidirectional_range, andrange_reference_t<Base>modelsbothbidirectional_rangeandcommon_rangecommon-bidirectional-range, theniterator_conceptdenotesbidirectional_iterator_tag.constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>common-bidirectional-range<range_reference_t<Base>>;-16- Effects: Equivalent to:
[…]constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>common-bidirectional-range<range_reference_t<Base>>;-17- Effects: Equivalent to:
[…]
Modify [range.join.with.view] as indicated:
namespace std::ranges {
template<class R>
concept bidirectional-common = bidirectional_range<R> && common_range<R>; // exposition only
[…]
}
Modify [range.join.with.iterator] as indicated:
namespace std::ranges { template<input_range V, forward_range Pattern> requires view<V> && input_range<range_reference_t<V>> && view<Pattern> && concatable<range_reference_t<V>, Pattern> template<bool Const> class join_with_view<V, Pattern>::iterator { private: […] public: […] constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-commoncommon-bidirectional-range<InnerBase> &&bidirectional-commoncommon-bidirectional-range<PatternBase>; constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-commoncommon-bidirectional-range<InnerBase> &&bidirectional-commoncommon-bidirectional-range<PatternBase>; […] }; }-1-
iterator::iterator_conceptis defined as follows::[…]
(1.1) — If
[…]ref-is-glvalueistrue,Basemodelsbidirectional_range, andInnerBaseandPatternBaseeach modelbidirectional-commoncommon-bidirectional-range, theniterator_conceptdenotesbidirectional_iterator_tag.constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-commoncommon-bidirectional-range<InnerBase> &&bidirectional-commoncommon-bidirectional-range<PatternBase>;[…]-16- Effects: Equivalent to:
constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> &&bidirectional-commoncommon-bidirectional-range<InnerBase> &&bidirectional-commoncommon-bidirectional-range<PatternBase>;-17- Effects: Equivalent to:
[…]
Modify [range.common.view] as indicated:
namespace std::ranges {
template<view V>
requires (!common_range<V> && copyable<iterator_t<V>>)
class common_view : public view_interface<common_view<V>> {
private:
V base_ = V(); // exposition only
public:
[…]
constexpr auto begin() requires (!simple-view<V>) {
if constexpr (random_access_range<V> && sized_range<V>sized-random-access-range<V>)
return ranges::begin(base_);
else
return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::begin(base_));
}
constexpr auto begin() const requires range<const V> {
if constexpr (random_access_range<const V> && sized_range<const V>sized-random-access-range<const V>)
return ranges::begin(base_);
else
return common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::begin(base_));
}
constexpr auto end() requires (!simple-view<V>) {
if constexpr (random_access_range<V> && sized_range<V>sized-random-access-range<V>)
return ranges::begin(base_) + ranges::distance(base_);
else
return common_iterator<iterator_t<V>, sentinel_t<V>>(ranges::end(base_));
}
constexpr auto end() const requires range<const V> {
if constexpr (random_access_range<const V> && sized_range<const V>sized-random-access-range<const V>)
return ranges::begin(base_) + ranges::distance(base_);
else
return common_iterator<iterator_t<const V>, sentinel_t<const V>>(ranges::end(base_));
}
[…]
};
[…]
}
Modify [range.zip.view] as indicated:
namespace std::ranges {
template<class... Rs>
concept zip-is-common = // exposition only
(sizeof...(Rs) == 1 && (common_range<Rs> && ...)) ||
(!(bidirectional_range<Rs> && ...) && (common_range<Rs> && ...)) ||
((random_access_range<Rs> && ...) && (sized_range<Rs> && ...)sized-random-access-range<Rs> && ...);
[…]
}
Modify [range.slide.view] as indicated:
namespace std::ranges {
template<class V>
concept slide-caches-nothing = random_access_range<V> && sized_range<V>sized-random-access-range<V>; // exposition only
template<class V>
concept slide-caches-last = // exposition only
!slide-caches-nothing<V> && bidirectional_range<V> && common_range<V>common-bidirectional-range<V>;
[…]
}
Modify [range.cartesian.view] as indicated:
namespace std::ranges {
template<bool Const, class First, class... Vs>
concept cartesian-product-is-random-access = // exposition only
(random_access_range<maybe-const<Const, First>> && ... &&
(random_access_range<maybe-const<Const, Vs>>
&& sized_range<maybe-const<Const, Vs>>)sized-random-access-range<maybe-const<Const, Vs>>);
template<class R>
concept cartesian-product-common-arg = // exposition only
common_range<R> || (sized_range<R> && random_access_range<R>)sized-random-access-range<R>;
[…]
}
[ 2025-10-23; Reflector poll. ]
Set priority to 4 after reflector poll.
Use of exposition-only concepts is not necessary improving readability or produced error messages.
P3179 introduces a new
exposition-only concept, sized-random-access-range, into <ranges> to simplify
the signature of parallel range algorithms.
However, this also applies more broadly to <ranges>, as we often need to determine whether a range satisfies
both sized_range and random_access_range in order to dispatch optimized branches.
common_range and
bidirectional_range to decide whether to provide backward traversal capabilities,
which is expressed by the exposition-only concept bidirectional-common introduced in
P2441.
Unfortunately, this concept currently only applies to a single section.
It would be much simpler and more readable if both concepts were available throughout <ranges>,
which would also allow newly introduced adapters or other library features to take advantage of them.
Note that since some of these simplifications change the order in which the concepts are spelled, they may not be
purely editorial.
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2025-10-23 09:34:52 | admin | set | messages: + msg15369 |
| 2025-08-02 13:17:27 | admin | set | messages: + msg14921 |
| 2025-07-28 00:00:00 | admin | create | |