Created on 2022-01-23.00:00:00 last changed 12 months ago
Proposed resolution:
This wording is relative to N4901.
[Drafting Note: Arthur thinks it's a bit "cute" of the Effects: element to static_cast from T(&)[N] to T* 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 an if constexpr (is_array_v...) or something like that.]
Modify [iterator.synopsis], header <iterator> synopsis, as indicated:
[…] // [range.iter.op.distance], ranges::distance template<classinput_or_output_iteratorI, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> distance(I first, S last); template<classinput_or_output_iteratorI, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<decay_t<I>> distance(constI&& first,constS&last); […]
Modify [range.iter.op.distance] as indicated:
template<classinput_or_output_iteratorI, 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<classinput_or_output_iteratorI, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<decay_t<I>> ranges::distance(constI&& first,constS&last);-3- Effects: Equivalent to: return last - static_cast<const decay_t<I>&>(first);
[ 2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Voting → WP. ]
[ Kona 2022-11-08; Move to Ready ]
[ 2022-02-16; Arthur and Casey provide improved wording ]
[ 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 that sentinel_for<S, I> already implies and subsumes input_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 the I's is constrained and the other isn't.]
Modify [iterator.synopsis], header <iterator> synopsis, as indicated:
[…] // [range.iter.op.distance], ranges::distance template<classinput_or_output_iteratorI, sentinel_for<I> S> requires (!sized_sentinel_for<S, I>) constexpr iter_difference_t<I> distance(I first, S last); template<classinput_or_output_iteratorI, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<I> distance(const I& first,constS&last); […]Modify [range.iter.op.distance] as indicated:
template<classinput_or_output_iteratorI, 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<classinput_or_output_iteratorI, sized_sentinel_for<decay_t<I>> S> constexpr iter_difference_t<I> ranges::distance(const I& first,constS&last);-3- Effects: Equivalent to: return last - first;
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.
History | |||
---|---|---|---|
Date | User | Action | Args |
2023-11-22 15:47:43 | admin | set | status: wp -> c++23 |
2023-02-13 10:17:57 | admin | set | messages: + msg13351 |
2023-02-13 10:17:57 | admin | set | status: voting -> wp |
2023-02-06 15:33:48 | admin | set | status: ready -> voting |
2022-11-10 23:33:23 | admin | set | messages: + msg13007 |
2022-11-10 23:33:23 | admin | set | status: new -> ready |
2022-02-18 16:36:17 | admin | set | messages: + msg12380 |
2022-01-30 17:05:36 | admin | set | messages: + msg12332 |
2022-01-23 16:07:48 | admin | set | messages: + msg12280 |
2022-01-23 00:00:00 | admin | create |