**Section:** 25.4.4.3 [range.iter.op.distance] **Status:** WP
**Submitter:** Arthur O'Dwyer **Opened:** 2022-01-23 **Last modified:** 2023-02-13 10:17:57 UTC

**Priority: **2

**View all other** issues in [range.iter.op.distance].

**View all issues with** WP status.

**Discussion:**

Consider the use of `std::ranges::distance(first, last)` on a simple C array.
This works fine with `std::distance`, but currently does not work with
`std::ranges::distance`.

// godbolt link #include <ranges> #include <cassert> int main() { int a[] = {1, 2, 3}; assert(std::ranges::distance(a, a+3) == 3); assert(std::ranges::distance(a, a) == 0); assert(std::ranges::distance(a+3, a) == -3); }

Before LWG 3392, we had a single iterator-pair overload:

template<input_or_output_iterator I, sentinel_for<I> S> constexpr iter_difference_t<I> distance(I first, S last);

which works fine for C pointers. After LWG 3392, we have two iterator-pair overloads:

template<input_or_output_iterator I, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> distance(I first, S last); template<input_or_output_iterator I, sized_sentinel_for<I> S> constexpr iter_difference_t<I> distance(const I& first, const S& last);

and unfortunately the one we want — `distance(I first, S last)` —
is no longer viable because [with `I=int*`, `S=int*`], we have
`sized_sentinel_for<S, I>` and so its constraints aren't satisfied.
So we look at the other overload [with `I=int[3]`, `S=int[3]`], but
unfortunately its constraints aren't satisfied either, because `int[3]`
is not an `input_or_output_iterator`.

*[2022-01-30; Reflector poll]*

Set priority to 2 after reflector poll.

**Previous resolution [SUPERSEDED]:**

This wording is relative to N4901.

[

Drafting Note:Thanks to Casey Carter. Notice thatsentinel_for<S, I>already implies and subsumesinput_or_output_iterator<I>, so that constraint wasn't doing anything; personally I'd prefer to remove it for symmetry (and to save the environment). Otherwise you'll have people asking why one of theI's is constrained and the other isn't.]

Modify 25.2 [iterator.synopsis], header

<iterator>synopsis, as indicated:[…]// 25.4.4.3 [range.iter.op.distance], ranges::distancetemplate<class~~input_or_output_iterator~~I, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> distance(I first, S last); template<class~~input_or_output_iterator~~I, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<I> distance(const I& first,~~const~~S~~&~~last); […]Modify 25.4.4.3 [range.iter.op.distance] as indicated:

template<class~~input_or_output_iterator~~I, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> ranges::distance(I first, S last);-1-

Preconditions:[first, last)denotes a range.-2-

Effects:Incrementsfirstuntillastis reached and returns the number of increments.template<class~~input_or_output_iterator~~I, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<I> ranges::distance(const I& first,~~const~~S~~&~~last);-3-

Effects:Equivalent to:return last - first;

*[2022-02-16; Arthur and Casey provide improved wording]*

*[Kona 2022-11-08; Move to Ready]*

*[2023-02-13 Status changed: Voting → WP.]*

**Proposed resolution:**

This wording is relative to N4901.

[

Drafting Note:Arthur thinks it's a bit "cute" of theEffects:element tostatic_castfromT(&)[N]toT* const&in the array case, but it does seem to do the right thing in all cases, and it saves us from having to use anif constexpr (is_array_v...)or something like that.]

Modify 25.2 [iterator.synopsis], header

`<iterator>`synopsis, as indicated:[…]

*// 25.4.4.3 [range.iter.op.distance], ranges::distance*template<class~~input_or_output_iterator~~I, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> distance(I first, S last); template<class~~input_or_output_iterator~~I, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<decay_t<I>> distance(~~const~~I&& first,~~const~~S~~&~~last); […]Modify 25.4.4.3 [range.iter.op.distance] as indicated:

template<class

~~input_or_output_iterator~~I, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> ranges::distance(I first, S last);-1-

*Preconditions:*`[first, last)`denotes a range.-2-

*Effects:*Increments`first`until`last`is reached and returns the number of increments.template<class

~~input_or_output_iterator~~I, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<decay_t<I>> ranges::distance(~~const~~I&& first,~~const~~S~~&~~last);-3-

*Effects:*Equivalent to:`return last - static_cast<const decay_t<I>&>(first);`