*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 preconditions**Section:** 25.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
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`

.