This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3306. `ranges::advance` violates its preconditions

Section: 23.4.4.2 [range.iter.op.advance] Status: WP Submitter: Casey Carter Opened: 2019-10-27 Last modified: 2020-11-09

Priority: 2

View all other issues in [range.iter.op.advance].

View all issues with WP 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 23.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.

1. Modify 23.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`.