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.

### 3607. `contiguous_iterator` should not be allowed to have custom `iter_move` and `iter_swap` behavior

Section: 25.3.4.14 [iterator.concept.contiguous] Status: WP Submitter: Tim Song Opened: 2021-09-28 Last modified: 2022-02-10

Priority: Not Prioritized

View all issues with WP status.

Discussion:

The `iter_move` and `iter_swap` customization points were introduced primarily for proxy iterators. Whatever their application to non-proxy iterators in general, they should not be allowed to have custom behavior for contiguous iterators — this new iterator category was introduced in large part to permit better optimizations, and allowing custom `iter_move/iter_swap` prevents such optimizations for a wide variety of algorithms that are specified to call them.

[2021-10-14; Reflector poll]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

[2022-02-10 Approved at February 2022 virtual plenary. Status changed: Tentatively Ready → WP.]

Proposed resolution:

This wording is relative to N4892.

1. Modify 25.3.4.14 [iterator.concept.contiguous] as indicated:

   >     template<class I>
   >       concept contiguous_iterator =
   >         random_access_iterator<I> &&
   >         derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> &&
   >         is_lvalue_reference_v<iter_reference_t<I>> &&
   >         same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> &&
   >         requires(const I& i) {
   >           { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>;
   >         };

   > > -2- Let `a` and `b` be dereferenceable iterators and `c` be a non-dereferenceable iterator of type `I` such that `b` is reachable from `a` and `c` is reachable from `b`, and let `D` be `iter_difference_t<I>`. The type `I` models `contiguous_iterator` only if

   > > 1. (2.1) — `to_address(a) == addressof(*a)`,

   > > 2. (2.2) — `to_address(b) == to_address(a) + D(b - a)`, and

   > > 3. (2.3) — `to_address(c) == to_address(a) + D(c - a)`.,

   > > 4. (2.?) — `ranges::iter_move(a)` has the same type, value category, and effects as `std::move(*a)`, and

   > > 5. (2.?) — if `ranges::iter_swap(a, b)` is well-formed, it has effects equivalent to `ranges::swap(*a, *b)`.