subrange::advance(n)
has UB when n < 0
Section: 25.5.4.3 [range.subrange.access] Status: C++23 Submitter: Casey Carter Opened: 2020-04-21 Last modified: 2023-11-22
Priority: 2
View all other issues in [range.subrange.access].
View all issues with C++23 status.
Discussion:
subrange::advance(n)
is specified to call ranges::advance(begin_, n, end_)
in both StoreSize
and !StoreSize
cases (25.5.4.3 [range.subrange.access]/9).
Unfortunately, ranges::advance(begin_, n, end_)
has undefined behavior when
n < 0
unless [end_, begin_)
denotes a valid range
(24.4.4.2 [range.iter.op.advance]/5). This would all be perfectly fine — the UB is exposed to
the caller via effects-equivalent-to — were it not the design intent that subrange::advance(-n)
be usable to reverse the effects of subrange::advance(n)
when the subrange
has a
bidirectional iterator type. That is, however, clearly the design intent: subrange::prev()
,
for example, is equivalent to subrange::advance(-1)
.
[2020-05-11; Reflector prioritization]
Set priority to 2 after reflector discussions.
[2021-01-15; Issue processing telecon]
Set status to Tentatively Ready after discussion and poll.
F | A | N |
---|---|---|
7 | 0 | 3 |
[2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready → WP.]
Proposed resolution:
This wording is relative to N4861.
Modify 25.5.4.3 [range.subrange.access] as indicated:
constexpr subrange& advance(iter_difference_t<I> n);-9- Effects: Equivalent to:
(9.1) — IfStoreSize
istrue
,auto d = n - ranges::advance(begin_, n, end_); if (d >= 0) size_ -= to-unsigned-like(d); else size_ += to-unsigned-like(-d); return *this;
(9.2) — Otherwise,ranges::advance(begin_, n, end_); return *this;if constexpr (bidirectional_iterator<I>) { if (n < 0) { ranges::advance(begin_, n); if constexpr (StoreSize) size_ += to-unsigned-like(-n); return *this; } } auto d = n - ranges::advance(begin_, n, end_); if constexpr (StoreSize) size_ -= to-unsigned-like(d); return *this;