**Section:** 25.4.4.2 [range.iter.op.advance] **Status:** C++23
**Submitter:** Casey Carter **Opened:** 2019-10-27 **Last modified:** 2023-11-22 15:47:43 UTC

**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
25.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 25.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`and`S`model`assignable_from<I&, S>`, equivalent to`i = std::move(bound)`.(4.2) — Otherwise, if

`S`and`I`model`sized_sentinel_for<S, I>`, equivalent to`ranges::advance(i, bound - i)`.(4.3) — Otherwise, while

`bool(i != bound)`is`true`, increments`i`.