iota_view::iterator::operator-
is overconstrainedSection: 25.6.4.3 [range.iota.iterator] Status: New Submitter: Hewill Kang Opened: 2023-01-06 Last modified: 2023-02-01
Priority: 3
View other active issues in [range.iota.iterator].
View all other issues in [range.iota.iterator].
View all issues with New status.
Discussion:
Currently, two iota_view::iterator
s can be subtracted
only when the underlying W
type models advanceable
,
where advanceable
consists of a series of syntactic and semantic
requirements similar to the random_access_iterator
concept.
However, when W
is an C++20 iterator type, whether it provides
subtraction is irrelevant to its iterator category.
In such cases, still requiring W
to support a series of random access
iterator-like operations seems too restrictive. Consider:
#include <list>
#include <ranges>
int main() {
std::list l{1, 2, 3, 4, 5};
auto it = std::counted_iterator(l.begin(), l.size());
auto r = std::views::iota(it, std::next(it, 3));
auto sz = r.size(); // 3 as expected
auto d = r.end() - r.begin(); // error: no match for 'operator-'
}
We can get the correct size of iota_view
by subtracting two
counted_iterator
s,
but we cannot subtract two iota_view::iterator
s to get their
difference, even though the underlying counted_iterator
already models
sized_sentinel_for
for itself, which is not satisfactory.
I think we should relax the constraints of
iota_view::iterator::operator-
to allow the above case,
which also makes it compatible with iota_view::sentinel::operator-
.
[2023-02-01; Reflector poll]
Set priority to 3 after reflector poll.
Several P0 votes, but an objection to P0 on the basis that we don't
define what it means to use sized_sentinel_for
on non-iterators.
Others responded that we don't need to, as we only use it with iterators,
and do not intend it to be usable with anything else.
Proposed resolution:
This wording is relative to N4917.
Modify 25.6.4.3 [range.iota.iterator] as indicated:
[…]namespace std::ranges { template<weakly_incrementable W, semiregular Bound> requires weakly-equality-comparable-with<W, Bound> && copyable<W> struct iota_view<W, Bound>::iterator { private: W value_ = W(); // exposition only public: […] friend constexpr iterator operator-(iterator i, difference_type n) requires advanceable<W>; friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires advanceable<W> || sized_sentinel_for<W, W>; }; }friend constexpr difference_type operator-(const iterator& x, const iterator& y) requires advanceable<W> || sized_sentinel_for<W, W>;-23- Effects: Equivalent to:
using D = difference_type; if constexpr (is-integer-like<W>) { if constexpr (is-signed-integer-like<W>) return D(D(x.value_) - D(y.value_)); else return (y.value_ > x.value_) ? D(-D(y.value_ - x.value_)) : D(x.value_ - y.value_); } else { return x.value_ - y.value_; }