17 Concepts library [concepts]

17.4 Language-related concepts [concepts.lang]

17.4.9 Concept Swappable [concept.swappable]

template<class T> concept Swappable = is_swappable_v<T>;
Let a1 and a2 denote distinct equal objects of type T, and let b1 and b2 similarly denote distinct equal objects of type T.
Swappable<T> is satisfied only if after evaluating either swap(a1, b1) or swap(b1, a1) in the context described below, a1 is equal to b2 and b1 is equal to a2.
The context in which swap(a1, b1) or swap(b1, a1) is evaluated shall ensure that a binary non-member function named swap is selected via overload resolution ([over.match]) on a candidate set that includes:
template<class T, class U> concept SwappableWith = is_swappable_with_v<T, T> && is_swappable_with_v<U, U> && CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> && is_swappable_with_v<T, U> && is_swappable_with_v<U, T>;
Let:
  • t1 and t2 denote distinct equal objects of type remove_­cvref_­t<T>,
  • be an expression that denotes t1 such that decltype(()) is T,
  • u1 and u2 similarly denote distinct equal objects of type remove_­cvref_­t<U>,
  • be an expression that denotes u1 such that decltype(()) is U, and
  • C be
        common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
SwappableWith<T, U> is satisfied only if after evaluating either swap(, ) or swap(, ) in the context described above, C(t1) is equal to C(u2) and C(u1) is equal to C(t2).
The context in which swap(, ) or swap(, ) is evaluated shall ensure that a binary non-member function named swap is selected via overload resolution ([over.match]) on a candidate set that includes:
[ 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>

template<class T, std::SwappableWith<T> U>
void value_swap(T&& t, U&& u) {
  using std::swap;
  swap(std::forward<T>(t), std::forward<U>(u)); // OK: uses “swappable with” conditions
                                                // for rvalues and lvalues
}

template<std::Swappable T>
void lv_swap(T& t1, T& t2) {
  using std::swap;
  swap(t1, t2);                                 // OK: uses swappable conditions for
}                                               // lvalues of type T

namespace N {
  struct A { int m; };
  struct Proxy { A* a; };
  Proxy proxy(A& a) { return Proxy{ &a }; }

  void swap(A& x, Proxy p) {
    std::swap(x.m, p.a->m);                     // OK: uses context equivalent to swappable
                                                // conditions for fundamental types
  }
  void swap(Proxy p, A& x) { swap(x, p); }      // satisfy symmetry constraint
}

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);
}
— end example
 ]