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&>()))