Let t1 and t2 be equality-preserving expressions that denote
distinct equal objects of type T, and let u1 and u2
similarly denote distinct equal objects of type U.

An operation
*exchanges the values* denoted by t1 and u1 if and only
if the operation modifies neither t2 nor u2 and:

- If T and U are different types and common_reference_with<decltype((t1)), decltype((u1))> is modeled, the result of the operation is that C(t1) equals C(u2) and C(u1) equals C(t2) where C is common_reference_t<decltype((t1)), decltype((u1))>.

The expression
ranges::swap(E1, E2) for subexpressions E1
and E2 is expression-equivalent to an expression
S determined as follows:

- S is (void)swap(E1, E2)208 if E1 or E2 has class or enumeration type ([basic.compound]) and that expression is valid, with overload resolution performed in a context that includes the declaration template<class T> void swap(T&, T&) = delete; and does not include a declaration of ranges::swap.If the function selected by overload resolution does not exchange the values denoted by E1 and E2, the program is ill-formed, no diagnostic required.
- Otherwise, if E1 and E2 are lvalues of array types ([basic.compound]) with equal extent and ranges::swap(*E1, *E2) is a valid expression, S is (void)ranges::swap_ranges(E1, E2), except that noexcept(S) is equal to noexcept(ranges::swap(*E1, *E2)).
- Otherwise, if E1 and E2 are lvalues of the same type T that models move_constructible<T> and assignable_from<T&, T>, S is an expression that exchanges the denoted values.S is a constant expression if
- T is a literal type ([basic.types.general]),
- both E1 = std::move(E2) and E2 = std::move(E1) are constant subexpressions ([defns.const.subexpr]), and
- the full-expressions of the initializers in the declarations T t1(std::move(E1)); T t2(std::move(E2)); are constant subexpressions.

```
template<class T, class U>
concept swappable_with =
common_reference_with<T, U> &&
requires(T&& t, U&& u) {
ranges::swap(std::forward<T>(t), std::forward<T>(t));
ranges::swap(std::forward<U>(u), std::forward<U>(u));
ranges::swap(std::forward<T>(t), std::forward<U>(u));
ranges::swap(std::forward<U>(u), std::forward<T>(t));
};
```

[*Note 4*: *end note*]

The semantics of the swappable and swappable_with
concepts are fully defined by the ranges::swap customization point object.

— [*Example 1*: *end example*]

User code can ensure that the evaluation of swap calls
is performed in an appropriate context under the various conditions as follows:
#include <cassert>
#include <concepts>
#include <utility>
namespace ranges = std::ranges;
template<class T, std::swappable_with<T> U>
void value_swap(T&& t, U&& u) {
ranges::swap(std::forward<T>(t), std::forward<U>(u));
}
template<std::swappable T>
void lv_swap(T& t1, T& t2) {
ranges::swap(t1, t2);
}
namespace N {
struct A { int m; };
struct Proxy {
A* a;
Proxy(A& a) : a{&a} {}
friend void swap(Proxy x, Proxy y) {
ranges::swap(*x.a, *y.a);
}
};
Proxy proxy(A& a) { return Proxy{ a }; }
}
int main() {
int i = 1, j = 2;
lv_swap(i, j);
assert(i == 2 && j == 1);
N::A a1 = { 5 }, a2 = { -5 };
value_swap(a1, proxy(a2));
assert(a1.m == -5 && a2.m == 5);
}

—