//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 // template // concept swappable_with = // see below #include #include #include #include #include #include #include #include #include #include #include #include #include #include "type_classification/moveconstructible.h" #include "type_classification/swappable.h" template constexpr bool check_swappable_with_impl() { static_assert(std::swappable_with == std::swappable_with); return std::swappable_with; } template constexpr bool check_swappable_with() { static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert( !check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert( !check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert( !check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert( !check_swappable_with_impl()); return check_swappable_with_impl(); } template constexpr bool check_swappable_with_including_lvalue_ref_to_volatile() { constexpr auto result = check_swappable_with(); static_assert(check_swappable_with_impl() == result); return result; } namespace fundamental { static_assert( check_swappable_with_including_lvalue_ref_to_volatile()); static_assert( check_swappable_with_including_lvalue_ref_to_volatile()); static_assert( !check_swappable_with_including_lvalue_ref_to_volatile()); static_assert( check_swappable_with_including_lvalue_ref_to_volatile()); static_assert( !check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (*)(), int (*)()>()); static_assert( !check_swappable_with_including_lvalue_ref_to_volatile()); struct S {}; static_assert(!check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int S::*, int S::*>()); static_assert( !check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)(), int (S::*)()>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int, int (S::*)()>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() noexcept, int (S::*)() noexcept>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() noexcept, int (S::*)()>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const, int (S::*)() const>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const, int (S::*)()>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const noexcept, int (S::*)() const noexcept>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const, int (S::*)() const noexcept>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() volatile, int (S::*)() volatile>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() volatile, int (S::*)()>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const volatile, int (S::*)() const volatile>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int (S::*)() const volatile, int (S::*)()>()); static_assert( check_swappable_with_including_lvalue_ref_to_volatile()); static_assert( !check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5], double[5]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5], double[6]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], double[5]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], double[6]>()); static_assert(check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], int[5][6]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], int[5][4]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], int[6][5]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], double[5][6]>()); static_assert(!check_swappable_with_including_lvalue_ref_to_volatile< int[5][6], double[6][5]>()); // always false static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); } // namespace fundamental namespace adl { static_assert( check_swappable_with()); static_assert(check_swappable_with()); static_assert(check_swappable_with()); static_assert( check_swappable_with_impl()); static_assert(!check_swappable_with_impl()); struct s1 {}; struct no_common_reference_with_s1 { friend void swap(s1&, no_common_reference_with_s1&); friend void swap(no_common_reference_with_s1&, s1&); }; static_assert(!check_swappable_with()); struct one_way_swappable_with_s1 { friend void swap(s1&, one_way_swappable_with_s1&); operator s1(); }; static_assert(std::common_reference_with); static_assert(!check_swappable_with()); struct one_way_swappable_with_s1_other_way { friend void swap(one_way_swappable_with_s1_other_way&, s1&); operator s1(); }; static_assert( std::common_reference_with); static_assert(!check_swappable_with()); struct can_swap_with_s1_but_not_swappable { can_swap_with_s1_but_not_swappable(can_swap_with_s1_but_not_swappable&&) = delete; friend void swap(s1&, can_swap_with_s1_but_not_swappable&); friend void swap(can_swap_with_s1_but_not_swappable&, s1&); operator s1() const; }; static_assert( std::common_reference_with); static_assert(!std::swappable); static_assert( !check_swappable_with()); struct swappable_with_s1 { friend void swap(s1&, swappable_with_s1&); friend void swap(swappable_with_s1&, s1&); operator s1() const; }; static_assert(check_swappable_with()); struct swappable_with_const_s1_but_not_swappable { swappable_with_const_s1_but_not_swappable( swappable_with_const_s1_but_not_swappable const&); swappable_with_const_s1_but_not_swappable( swappable_with_const_s1_but_not_swappable const&&); swappable_with_const_s1_but_not_swappable& operator=(swappable_with_const_s1_but_not_swappable const&); swappable_with_const_s1_but_not_swappable& operator=(swappable_with_const_s1_but_not_swappable const&&); friend void swap(s1 const&, swappable_with_const_s1_but_not_swappable const&); friend void swap(swappable_with_const_s1_but_not_swappable const&, s1 const&); operator s1 const &() const; }; static_assert( !std::swappable); static_assert(!std::swappable_with< swappable_with_const_s1_but_not_swappable const&, s1 const&>); struct swappable_with_volatile_s1_but_not_swappable { swappable_with_volatile_s1_but_not_swappable( swappable_with_volatile_s1_but_not_swappable volatile&); swappable_with_volatile_s1_but_not_swappable( swappable_with_volatile_s1_but_not_swappable volatile&&); swappable_with_volatile_s1_but_not_swappable& operator=(swappable_with_volatile_s1_but_not_swappable volatile&); swappable_with_volatile_s1_but_not_swappable& operator=(swappable_with_volatile_s1_but_not_swappable volatile&&); friend void swap(s1 volatile&, swappable_with_volatile_s1_but_not_swappable volatile&); friend void swap(swappable_with_volatile_s1_but_not_swappable volatile&, s1 volatile&); operator s1 volatile &() volatile; }; static_assert( !std::swappable); static_assert( !std::swappable_with); struct swappable_with_cv_s1_but_not_swappable { swappable_with_cv_s1_but_not_swappable( swappable_with_cv_s1_but_not_swappable const volatile&); swappable_with_cv_s1_but_not_swappable( swappable_with_cv_s1_but_not_swappable const volatile&&); swappable_with_cv_s1_but_not_swappable& operator=(swappable_with_cv_s1_but_not_swappable const volatile&); swappable_with_cv_s1_but_not_swappable& operator=(swappable_with_cv_s1_but_not_swappable const volatile&&); friend void swap(s1 const volatile&, swappable_with_cv_s1_but_not_swappable const volatile&); friend void swap(swappable_with_cv_s1_but_not_swappable const volatile&, s1 const volatile&); operator s1 const volatile &() const volatile; }; static_assert( !std::swappable); static_assert( !std::swappable_with); struct s2 { friend void swap(s2 const&, s2 const&); friend void swap(s2 volatile&, s2 volatile&); friend void swap(s2 const volatile&, s2 const volatile&); }; struct swappable_with_const_s2 { swappable_with_const_s2(swappable_with_const_s2 const&); swappable_with_const_s2(swappable_with_const_s2 const&&); swappable_with_const_s2& operator=(swappable_with_const_s2 const&); swappable_with_const_s2& operator=(swappable_with_const_s2 const&&); friend void swap(swappable_with_const_s2 const&, swappable_with_const_s2 const&); friend void swap(s2 const&, swappable_with_const_s2 const&); friend void swap(swappable_with_const_s2 const&, s2 const&); operator s2 const &() const; }; static_assert(std::swappable_with); struct swappable_with_volatile_s2 { swappable_with_volatile_s2(swappable_with_volatile_s2 volatile&); swappable_with_volatile_s2(swappable_with_volatile_s2 volatile&&); swappable_with_volatile_s2& operator=(swappable_with_volatile_s2 volatile&); swappable_with_volatile_s2& operator=(swappable_with_volatile_s2 volatile&&); friend void swap(swappable_with_volatile_s2 volatile&, swappable_with_volatile_s2 volatile&); friend void swap(s2 volatile&, swappable_with_volatile_s2 volatile&); friend void swap(swappable_with_volatile_s2 volatile&, s2 volatile&); operator s2 volatile &() volatile; }; static_assert( std::swappable_with); struct swappable_with_cv_s2 { swappable_with_cv_s2(swappable_with_cv_s2 const volatile&); swappable_with_cv_s2(swappable_with_cv_s2 const volatile&&); swappable_with_cv_s2& operator=(swappable_with_cv_s2 const volatile&); swappable_with_cv_s2& operator=(swappable_with_cv_s2 const volatile&&); friend void swap(swappable_with_cv_s2 const volatile&, swappable_with_cv_s2 const volatile&); friend void swap(s2 const volatile&, swappable_with_cv_s2 const volatile&); friend void swap(swappable_with_cv_s2 const volatile&, s2 const volatile&); operator s2 const volatile &() const volatile; }; static_assert(std::swappable_with); struct swappable_with_rvalue_ref_to_s1_but_not_swappable { friend void swap(swappable_with_rvalue_ref_to_s1_but_not_swappable&&, swappable_with_rvalue_ref_to_s1_but_not_swappable&&); friend void swap(s1&&, swappable_with_rvalue_ref_to_s1_but_not_swappable&&); friend void swap(swappable_with_rvalue_ref_to_s1_but_not_swappable&&, s1&&); operator s1() const; }; static_assert( !std::swappable); static_assert( !std::swappable_with< swappable_with_rvalue_ref_to_s1_but_not_swappable const&&, s1 const&&>); struct swappable_with_rvalue_ref_to_const_s1_but_not_swappable { friend void swap(s1 const&&, swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&); friend void swap(swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&, s1 const&&); operator s1 const() const; }; static_assert(!std::swappable< swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&>); static_assert(!std::swappable_with< swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&, s1 const&&>); struct swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable { swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable( swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&); swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable( swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&); swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable& operator=( swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&); swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable& operator=( swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&); friend void swap(s1 volatile&&, swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&); friend void swap(swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&, s1 volatile&&); operator s1 volatile &&() volatile&&; }; static_assert( !std::swappable< swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&>); static_assert( !std::swappable_with< swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&, s1 volatile&&>); struct swappable_with_rvalue_ref_to_cv_s1_but_not_swappable { swappable_with_rvalue_ref_to_cv_s1_but_not_swappable( swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&); swappable_with_rvalue_ref_to_cv_s1_but_not_swappable( swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&); swappable_with_rvalue_ref_to_cv_s1_but_not_swappable& operator=( swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&); swappable_with_rvalue_ref_to_cv_s1_but_not_swappable& operator=( swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&); friend void swap(s1 const volatile&&, swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&); friend void swap(swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&, s1 const volatile&&); operator s1 const volatile &&() const volatile&&; }; static_assert( !std::swappable< swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&>); static_assert( !std::swappable_with< swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&, s1 const volatile&&>); struct s3 { friend void swap(s3&&, s3&&); friend void swap(s3 const&&, s3 const&&); friend void swap(s3 volatile&&, s3 volatile&&); friend void swap(s3 const volatile&&, s3 const volatile&&); }; struct swappable_with_rvalue_ref_to_s3 { friend void swap(swappable_with_rvalue_ref_to_s3&&, swappable_with_rvalue_ref_to_s3&&); friend void swap(s3&&, swappable_with_rvalue_ref_to_s3&&); friend void swap(swappable_with_rvalue_ref_to_s3&&, s3&&); operator s3() const; }; static_assert(std::swappable_with); struct swappable_with_rvalue_ref_to_const_s3 { swappable_with_rvalue_ref_to_const_s3( swappable_with_rvalue_ref_to_const_s3 const&); swappable_with_rvalue_ref_to_const_s3( swappable_with_rvalue_ref_to_const_s3 const&&); swappable_with_rvalue_ref_to_const_s3& operator=(swappable_with_rvalue_ref_to_const_s3 const&); swappable_with_rvalue_ref_to_const_s3& operator=(swappable_with_rvalue_ref_to_const_s3 const&&); friend void swap(swappable_with_rvalue_ref_to_const_s3 const&&, swappable_with_rvalue_ref_to_const_s3 const&&); friend void swap(s3 const&&, swappable_with_rvalue_ref_to_const_s3 const&&); friend void swap(swappable_with_rvalue_ref_to_const_s3 const&&, s3 const&&); operator s3() const; }; static_assert(std::swappable_with); struct swappable_with_rvalue_ref_to_volatile_s3 { swappable_with_rvalue_ref_to_volatile_s3( swappable_with_rvalue_ref_to_volatile_s3 volatile&); swappable_with_rvalue_ref_to_volatile_s3( swappable_with_rvalue_ref_to_volatile_s3 volatile&&); swappable_with_rvalue_ref_to_volatile_s3& operator=(swappable_with_rvalue_ref_to_volatile_s3 volatile&); swappable_with_rvalue_ref_to_volatile_s3& operator=(swappable_with_rvalue_ref_to_volatile_s3 volatile&&); friend void swap(swappable_with_rvalue_ref_to_volatile_s3 volatile&&, swappable_with_rvalue_ref_to_volatile_s3 volatile&&); friend void swap(s3 volatile&&, swappable_with_rvalue_ref_to_volatile_s3 volatile&&); friend void swap(swappable_with_rvalue_ref_to_volatile_s3 volatile&&, s3 volatile&&); operator s3 volatile &&() volatile; }; static_assert( std::swappable_with); struct swappable_with_rvalue_ref_to_cv_s3 { swappable_with_rvalue_ref_to_cv_s3( swappable_with_rvalue_ref_to_cv_s3 const volatile&); swappable_with_rvalue_ref_to_cv_s3( swappable_with_rvalue_ref_to_cv_s3 const volatile&&); swappable_with_rvalue_ref_to_cv_s3& operator=(swappable_with_rvalue_ref_to_cv_s3 const volatile&); swappable_with_rvalue_ref_to_cv_s3& operator=(swappable_with_rvalue_ref_to_cv_s3 const volatile&&); friend void swap(swappable_with_rvalue_ref_to_cv_s3 const volatile&&, swappable_with_rvalue_ref_to_cv_s3 const volatile&&); friend void swap(s3 const volatile&&, swappable_with_rvalue_ref_to_cv_s3 const volatile&&); friend void swap(swappable_with_rvalue_ref_to_cv_s3 const volatile&&, s3 const volatile&&); operator s3 const volatile &&() const volatile; }; static_assert( std::swappable_with); namespace union_swap { union adl_swappable { int x; double y; operator int() const; }; void swap(adl_swappable&, adl_swappable&) noexcept; void swap(adl_swappable&&, adl_swappable&&) noexcept; void swap(adl_swappable&, int&) noexcept; void swap(int&, adl_swappable&) noexcept; } // namespace union_swap static_assert( std::swappable_with); static_assert(std::swappable_with); static_assert(std::swappable_with); static_assert(std::swappable_with); } // namespace adl namespace standard_types { static_assert( check_swappable_with, std::array >()); static_assert( !check_swappable_with, std::array >()); static_assert(check_swappable_with, std::deque >()); static_assert(!check_swappable_with, std::vector >()); static_assert( check_swappable_with, std::forward_list >()); static_assert( !check_swappable_with, std::vector >()); static_assert(check_swappable_with, std::list >()); static_assert(!check_swappable_with, std::vector >()); static_assert( check_swappable_with, std::map >()); static_assert(!check_swappable_with, std::vector >()); static_assert(check_swappable_with >, std::optional > >()); static_assert(!check_swappable_with >, std::vector >()); static_assert(check_swappable_with, std::vector >()); static_assert(!check_swappable_with, int>()); } // namespace standard_types namespace types_with_purpose { static_assert(!check_swappable_with()); static_assert(!check_swappable_with()); static_assert(!check_swappable_with()); static_assert(!check_swappable_with()); static_assert(!check_swappable_with()); static_assert( !check_swappable_with()); static_assert(!check_swappable_with()); } // namespace types_with_purpose namespace LWG3175 { // Example taken directly from [concept.swappable] template U> constexpr void value_swap(T&& t, U&& u) { std::ranges::swap(std::forward(t), std::forward(u)); } template constexpr void lv_swap(T& t1, T& t2) { std::ranges::swap(t1, t2); } namespace N { struct A { int m; }; struct Proxy { A* a; constexpr Proxy(A& a_) : a{&a_} {} friend constexpr void swap(Proxy x, Proxy y) { std::ranges::swap(*x.a, *y.a); } }; constexpr Proxy proxy(A& a) { return Proxy{a}; } } // namespace N constexpr bool CheckRegression() { 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); return true; } static_assert(CheckRegression()); } // namespace LWG3175