This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
std::ranges::size in ranges algorithmsSection: 26.2 [algorithms.requirements] Status: New Submitter: Ruslan Arutyunyan Opened: 2025-12-12 Last modified: 2025-12-20
Priority: Not Prioritized
View other active issues in [algorithms.requirements].
View all other issues in [algorithms.requirements].
View all issues with New status.
Discussion:
26.2 [algorithms.requirements] paragraph 14 says that the algorithms in ranges namespace are implemented
as if they are dispatched to the corresponding overload with iterator and sentinel. However, there are two problems
with the current wording:
We only allow to call either std::ranges::end(r) or std::ranges::next(std::ranges::begin(r), std::ranges::end())
to calculate a corresponding sentinel. However, this is a pessimization for some ranges because we can have sized
ranges without sized_sentinel_for. Consider the following example:
const char str[] = "something";
ranges::subrange<const char*,
null_sentinel_t,
subrange_kind::sized> sr(ranges::begin(str),
null_sentinel,
ranges::size(str) - 1);
my::ranges::next(sr.begin(), sr.end()); // this line serially calculates iterator that is equal to sr.end()
Despite the fact that we know the size of the range and that the range is the random access one,
std::ranges::next calculates the iterator serially, because it only has constant time complexity
optimization for sized_sentinel_for. We could clearly achieve better complexity with a different
API or with the different overload of the same API.
It is unclear when an algorithm calls std::ranges::end(r) and when it calls
std::ranges::next(std::ranges::begin(r), std::ranges::end()) to calculate the
corresponding sentinel because there is no established priority between them.
Maybe, it's smaller problem but still it's worth clarifying in my opinion.
Proposed resolution:
This wording is relative to N5032.
Modify 26.2 [algorithms.requirements] as indicated:
[…]
-14- Overloads of algorithms that takerangearguments (25.4.2 [range.range]) behave as if they are implemented by dispatching to the overload in namespacerangesthat takes separate iterator and sentinel arguments, where for each range argumentr
(14.1) — a corresponding iterator argument is initialized with
ranges::begin(r)and(14.2) — a corresponding sentinel argument is initialized with
one of the following:ranges::end(r), orranges::next(ranges::begin(r), ranges::end(r))if the type ofrmodelsforward_rangeand computingranges::nextmeets the specified complexity requirements.
(14.2.1) — if the type of
rmodelsforward_rangeand computingranges::nextmeets the specified complexity requirements then
(14.2.1.1) —
ranges::next(ranges::begin(r), ranges::size(r))ifrmodelssized_range, otherwise(14.2.1.2) —
ranges::next(ranges::begin(r), ranges::end(r)).(14.2.2) — Otherwise,
std::ranges::end(s).