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.

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

Section: [iterator.concept.contiguous] Status: C++23 Submitter: Tim Song Opened: 2021-09-28 Last modified: 2023-11-22

Priority: Not Prioritized

View all issues with C++23 status.


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 [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).