This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Open status.

4490. Allow calling std::ranges::size in ranges algorithms

Section: 26.2 [algorithms.requirements] Status: Open Submitter: Ruslan Arutyunyan Opened: 2025-12-12 Last modified: 2026-02-02

Priority: 3

View other active issues in [algorithms.requirements].

View all other issues in [algorithms.requirements].

View all issues with Open 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:

  1. 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.

  2. 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.

[2026-01-16; Reflector poll.]

Set priority to 3 after reflector poll.

"Should be 'the type of r models sized_range"

"It's a lot of words, could be shorter. Would prefer not to establish priority, but let implementation decide if/when to use ranges::next."

"Would counted_iterator(ranges::begin(r), ranges::distance(r)) and default_sentinel be better?"

Previous resolution [SUPERSEDED]:

This wording is relative to N5032.

  1. Modify 26.2 [algorithms.requirements] as indicated:

    […]

    -14- Overloads of algorithms that take range arguments (25.4.2 [range.range]) behave as if they are implemented by dispatching to the overload in namespace ranges that takes separate iterator and sentinel arguments, where for each range argument r

    • (14.1) — a corresponding iterator argument is initialized with ranges::begin(r) and

    • (14.2) — a corresponding sentinel argument is initialized with ranges::end(r), or ranges::next(ranges::begin(r), ranges::end(r)) if the type of r models forward_range and computing ranges::next meets the specified complexity requirements.one of the following:

      • (14.2.1) — if the type of r models forward_range and computing ranges::next meets the specified complexity requirements then

        • (14.2.1.1) — ranges::next(ranges::begin(r), ranges::size(r)) if r models sized_range, otherwise

        • (14.2.1.2) — ranges::next(ranges::begin(r), ranges::end(r)).

      • (14.2.2) — Otherwise, std::ranges::end(s).

[2026-01-30; Jonathan provides new wording]

We can just say that the value is either the end iterator, or begin+N, without saying when or how the implementation obtains begin+N. It might use ranges::next(ranges::begin(r), std::ranges::end(r)) or ranges::next(ranges::begin(r), ranges::distance(r)) or something else, only the value matters not how it's obtained. Paragraph 11 in the same subclause defines what begin+N means if the iterator is not a random access iterator.

[2026-01-30; LWG telecon. Status → Open.]

Proposed resolution:

This wording is relative to N5032.

  1. Modify 26.2 [algorithms.requirements] as indicated:

    […]

    -14- Overloads of algorithms that take range arguments (25.4.2 [range.range]) behave as if they are implemented by dispatching to the overload in namespace ranges that takes separate iterator and sentinel arguments, where for each range argument r

    • (14.1) — a corresponding iterator argument is initialized with ranges::begin(r) and

    • (14.2) — a corresponding sentinel argument is initialized with ranges::end(r), or ranges::next(ranges::begin(r), ranges::end(r)) if the type of r models forward_range and computing ranges::next meets the specified complexity requirements. ranges::begin(r) + N where N is equal to ranges::distance(r).