9 Iterators library [iterators]

9.3 Iterator requirements [iterator.requirements]

9.3.2 Customization points [iterator.custpoints]

9.3.2.1 iter_move [iterator.custpoints.iter_move]

The name iter_move denotes a customization point object ([customization.point.object]). The expression ranges::iter_move(E) for some subexpression E is expression-equivalent to the following:

  • static_cast<decltype(iter_move(E))>(iter_move(E)), if that expression is well-formed when evaluated in a context that does not include ranges::iter_move but does include the lookup set produced by argument-dependent lookup ( ISO/IEC 14882:2014 §[basic.lookup.argdep]).

  • Otherwise, if the expression *E is well-formed:

    • if *E is an lvalue, std::move(*E);

    • otherwise, static_cast<decltype(*E)>(*E).

  • Otherwise, ranges::iter_move(E) is ill-formed.

If ranges::iter_move(E) does not equal *E, the program is ill-formed with no diagnostic required.

9.3.2.2 iter_swap [iterator.custpoints.iter_swap]

The name iter_swap denotes a customization point object ([customization.point.object]). The expression ranges::iter_swap(E1, E2) for some subexpressions E1 and E2 is expression-equivalent to the following:

  • (void)iter_swap(E1, E2), if that expression is well-formed when evaluated in a context that does not include ranges::iter_swap but does include the lookup set produced by argument-dependent lookup ( ISO/IEC 14882:2014 §[basic.lookup.argdep]) and the following declaration:

    void iter_swap(auto, auto) = delete;
    
  • Otherwise, if the types of E1 and E2 both satisfy Readable, and if the reference type of E1 is swappable with ([concepts.lib.corelang.swappable]) the reference type of E2, then ranges::swap(*E1, *E2)

  • Otherwise, if the types T1 and T2 of E1 and E2 satisfy IndirectlyMovableStorable<T1, T2> && IndirectlyMovableStorable<T2, T1>, (void)(*E1 = iter_exchange_move(E2, E1)), except that E1 is evaluated only once.

  • Otherwise, ranges::iter_swap(E1, E2) is ill-formed.

If ranges::iter_swap(E1, E2) does not swap the values denoted by the expressions E1 and E2, the program is ill-formed with no diagnostic required.

iter_exchange_move is an exposition-only function specified as: template <class X, class Y> constexpr value_type_t<remove_reference_t<X>> iter_exchange_move(X&& x, Y&& y) noexcept(see below);

Effects: Equivalent to:

value_type_t<remove_reference_t<X>> old_value(iter_move(x));
*x = iter_move(y);
return old_value;

Remarks: The expression in the noexcept is equivalent to:

NE(remove_reference_t<X>, remove_reference_t<Y>) &&
NE(remove_reference_t<Y>, remove_reference_t<X>)

Where NE(T1, T2) is the expression:

is_nothrow_constructible<value_type_t<T1>, rvalue_reference_t<T1>>::value &&
is_nothrow_assignable<value_type_t<T1>&, rvalue_reference_t<T1>>::value &&
is_nothrow_assignable<reference_t<T1>, rvalue_reference_t<T2>>::value &&
is_nothrow_assignable<reference_t<T1>, value_type_t<T2>>::value> &&
is_nothrow_move_constructible<value_type_t<T1>>::value &&
noexcept(ranges::iter_move(declval<T1&>()))