This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++23 status.
ranges::advance
violates its preconditionsSection: 24.4.4.2 [range.iter.op.advance] Status: C++23 Submitter: Casey Carter Opened: 2019-10-27 Last modified: 2023-11-22
Priority: 2
View all other issues in [range.iter.op.advance].
View all issues with C++23 status.
Discussion:
Recall that "[i, s)
denotes a range" for an iterator i
and sentinel s
means that either i == s
holds, or i
is dereferenceable and [++i, s)
denotes a range ( [iterator.requirements.genera]).
The three-argument overload ranges::advance(i, n, bound)
is specified in
24.4.4.2 [range.iter.op.advance] paragraphs 5 through 7. Para 5 establishes a precondition that
[bound, i)
denotes a range when n < 0
(both bound
and i
must
have the same type in this case). When sized_sentinel_for<S, I>
holds and
n < bound - i
, para 6.1.1 says that ranges::advance(i, n, bound)
is equivalent
to ranges::advance(i, bound)
. Para 3, however, establishes a precondition for
ranges::advance(i, bound)
that [i, bound)
denotes a range. [bound, i)
and
[i, bound)
cannot both denote ranges unless i == bound
, which is not the case for
all calls that reach 6.1.1.
The call in para 6.1.1 wants the effects of either 4.1 - which really has no preconditions - or 4.2,
which is well-defined if either [i, bound)
or [bound, i)
denotes a range. Para 3's
stronger precondition is actually only required by Para 4.3, which increments i
blindly
looking for bound
. The straight-forward fix here seems to be to relax para 3's precondition
to only apply when 4.3 will be reached.
[2019-11 Priority to 2 during Monday issue prioritization in Belfast]
[2020-08-21 Issue processing telecon: moved to Tentatively Ready]
[2020-11-09 Approved In November virtual meeting. Status changed: Tentatively Ready → WP.]
Proposed resolution:
This wording is relative to N4835.
Modify 24.4.4.2 [range.iter.op.advance] as indicated:
template<input_or_output_iterator I, sentinel_for<I> S> constexpr void ranges::advance(I& i, S bound);-3- Expects: Either
assignable_from<I&, S> || sized_sentinel_for<S, I>
is modeled, or[i, bound)
denotes a range.-4- Effects:
(4.1) — If
I
andS
modelassignable_from<I&, S>
, equivalent toi = std::move(bound)
.(4.2) — Otherwise, if
S
andI
modelsized_sentinel_for<S, I>
, equivalent toranges::advance(i, bound - i)
.(4.3) — Otherwise, while
bool(i != bound)
istrue
, incrementsi
.