3559. Semantic requirements of sized_range is circular

Section: 25.4.3 [range.sized] Status: C++23 Submitter: Tim Song Opened: 2021-06-03 Last modified: 2023-11-22

Priority: Not Prioritized

View all other issues in [range.sized].

View all issues with C++23 status.

Discussion:

25.4.3 [range.sized] p2.1 requires that for a sized_range t, ranges::size(t) is equal to ranges::distance(t). But for a sized_range, ranges::distance(t) is simply ranges::size(t) cast to the difference type.

Presumably what we meant is that distance(begin, end) — the actual distance you get from traversing the range — is equal to what ranges::size produces, and not merely that casting from the size type to difference type is value-preserving. Otherwise, sized_range would be more or less meaningless.

[2021-06-14; Reflector poll]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

[2021-10-14 Approved at October 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4885.

  1. Modify 25.4.3 [range.sized] as indicated:

    template<class T>
      concept sized_range =
        range<T> &&
        requires(T& t) { ranges::size(t); };
    

    -2- Given an lvalue t of type remove_reference_t<T>, T models sized_range only if

    1. (2.1) — ranges::size(t) is amortized 𝒪(1), does not modify t, and is equal to ranges::distance(ranges::begin(t), ranges::end(t)t), and

    2. (2.2) — if iterator_t<T> models forward_iterator, ranges::size(t) is well-defined regardless of the evaluation of ranges::begin(t).