forked from OSchip/llvm-project
[libcxx] adds std::ranges::swap, std::swappable, and std::swappable_with
Implements parts of: - P0898R3 Standard Library Concepts - P1754 Rename concepts to standard_case for C++20, while we still can Depends on D96742 Differential Revision: https://reviews.llvm.org/D97162
This commit is contained in:
parent
469d5462fa
commit
c744332793
|
@ -251,6 +251,89 @@ concept copy_constructible =
|
|||
constructible_from<_Tp, const _Tp&> && convertible_to<const _Tp&, _Tp> &&
|
||||
constructible_from<_Tp, const _Tp> && convertible_to<const _Tp, _Tp>;
|
||||
|
||||
// [concept.swappable]
|
||||
namespace ranges::__swap {
|
||||
// Deleted to inhibit ADL
|
||||
template<class _Tp>
|
||||
void swap(_Tp&, _Tp&) = delete;
|
||||
|
||||
template<class _Tp>
|
||||
concept __class_or_enum = is_class_v<_Tp> || is_union_v<_Tp> || is_enum_v<_Tp>;
|
||||
|
||||
// [1]
|
||||
template<class _Tp, class _Up>
|
||||
concept __unqualified_swappable_with =
|
||||
(__class_or_enum<remove_cvref_t<_Tp>> || __class_or_enum<remove_cvref_t<_Up>>) &&
|
||||
requires(_Tp&& __t, _Up&& __u) {
|
||||
swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u));
|
||||
};
|
||||
|
||||
struct __fn;
|
||||
|
||||
template<class _Tp, class _Up, size_t _Size>
|
||||
concept __swappable_arrays =
|
||||
!__unqualified_swappable_with<_Tp(&)[_Size], _Up(&)[_Size]> &&
|
||||
extent_v<_Tp> == extent_v<_Up> &&
|
||||
requires(_Tp(& __t)[_Size], _Up(& __u)[_Size], const __fn& __swap) {
|
||||
__swap(__t[0], __u[0]);
|
||||
};
|
||||
|
||||
template<class _Tp>
|
||||
concept __exchangeable =
|
||||
!__unqualified_swappable_with<_Tp&, _Tp&> &&
|
||||
move_constructible<_Tp> &&
|
||||
assignable_from<_Tp&, _Tp>;
|
||||
|
||||
struct __fn {
|
||||
// 2.1 `S` is `(void)swap(E1, E2)`* if `E1` or `E2` has class or enumeration type and...
|
||||
// *The name `swap` is used here unqualified.
|
||||
template<class _Tp, class _Up>
|
||||
requires __unqualified_swappable_with<_Tp, _Up>
|
||||
constexpr void operator()(_Tp&& __t, _Up&& __u) const
|
||||
noexcept(noexcept(swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u))))
|
||||
{
|
||||
swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u));
|
||||
}
|
||||
|
||||
// 2.2 Otherwise, if `E1` and `E2` are lvalues of array types with equal extent and...
|
||||
template<class _Tp, class _Up, size_t _Size>
|
||||
requires __swappable_arrays<_Tp, _Up, _Size>
|
||||
constexpr void operator()(_Tp(& __t)[_Size], _Up(& __u)[_Size]) const
|
||||
noexcept(noexcept((*this)(*__t, *__u)))
|
||||
{
|
||||
// TODO(cjdb): replace with `ranges::swap_ranges`.
|
||||
for (size_t __i = 0; __i < _Size; ++__i) {
|
||||
(*this)(__t[__i], __u[__i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 2.3 Otherwise, if `E1` and `E2` are lvalues of the same type `T` that models...
|
||||
template<__exchangeable _Tp>
|
||||
constexpr void operator()(_Tp& __x, _Tp& __y) const
|
||||
noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_move_assignable_v<_Tp>)
|
||||
{
|
||||
__y = _VSTD::exchange(__x, _VSTD::move(__y));
|
||||
}
|
||||
};
|
||||
} // namespace ranges::__swap
|
||||
|
||||
namespace ranges::inline __cpo {
|
||||
inline constexpr auto swap = __swap::__fn{};
|
||||
} // namespace ranges::__cpo
|
||||
|
||||
template<class _Tp>
|
||||
concept swappable = requires(_Tp& __a, _Tp& __b) { ranges::swap(__a, __b); };
|
||||
|
||||
template<class _Tp, class _Up>
|
||||
concept swappable_with =
|
||||
common_reference_with<_Tp&, _Up&> &&
|
||||
requires(_Tp&& __t, _Up&& __u) {
|
||||
ranges::swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Tp>(__t));
|
||||
ranges::swap(_VSTD::forward<_Up>(__u), _VSTD::forward<_Up>(__u));
|
||||
ranges::swap(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Up>(__u));
|
||||
ranges::swap(_VSTD::forward<_Up>(__u), _VSTD::forward<_Tp>(__t));
|
||||
};
|
||||
|
||||
// [concept.booleantestable]
|
||||
template<class _Tp>
|
||||
concept __boolean_testable_impl = convertible_to<_Tp, bool>;
|
||||
|
|
|
@ -28,6 +28,7 @@ struct CustomMoveAssign {
|
|||
|
||||
struct DeletedMoveCtor {
|
||||
DeletedMoveCtor(DeletedMoveCtor&&) = delete;
|
||||
DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default;
|
||||
};
|
||||
|
||||
struct ImplicitlyDeletedMoveCtor {
|
||||
|
@ -35,7 +36,7 @@ struct ImplicitlyDeletedMoveCtor {
|
|||
};
|
||||
|
||||
struct DeletedMoveAssign {
|
||||
DeletedMoveAssign& operator=(DeletedMoveAssign&&) = default;
|
||||
DeletedMoveAssign& operator=(DeletedMoveAssign&&) = delete;
|
||||
};
|
||||
|
||||
struct ImplicitlyDeletedMoveAssign {
|
||||
|
@ -58,4 +59,16 @@ private:
|
|||
int&& X;
|
||||
};
|
||||
|
||||
struct NonMovable {
|
||||
NonMovable() = default;
|
||||
NonMovable(NonMovable&&) = delete;
|
||||
NonMovable& operator=(NonMovable&&) = delete;
|
||||
};
|
||||
|
||||
struct DerivedFromNonMovable : NonMovable {};
|
||||
|
||||
struct HasANonMovable {
|
||||
NonMovable X;
|
||||
};
|
||||
|
||||
#endif // TEST_STD_CONCEPTS_LAND_MOVECONSTRUCTIBLE_H
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef TEST_STD_CONCEPTS_LANG_SWAPPABLE_H
|
||||
#define TEST_STD_CONCEPTS_LANG_SWAPPABLE_H
|
||||
|
||||
#include <concepts>
|
||||
|
||||
// `adl_swappable` indicates it's been swapped using ADL by maintaining a pointer to itself that
|
||||
// isn't a part of the exchange. This is well-formed since we say that two `adl_swappable` objects
|
||||
// are equal only if their respective `value` subobjects are equal and their respective `this`
|
||||
// subobjects store the addresses of those respective `adl_swappable` objects.
|
||||
class lvalue_adl_swappable {
|
||||
public:
|
||||
lvalue_adl_swappable() = default;
|
||||
|
||||
constexpr lvalue_adl_swappable(int value) noexcept : value_(value) {}
|
||||
|
||||
constexpr lvalue_adl_swappable(lvalue_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr lvalue_adl_swappable(lvalue_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr lvalue_adl_swappable&
|
||||
operator=(lvalue_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(lvalue_adl_swappable& x,
|
||||
lvalue_adl_swappable& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool operator==(lvalue_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
lvalue_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class lvalue_rvalue_adl_swappable {
|
||||
public:
|
||||
lvalue_rvalue_adl_swappable() = default;
|
||||
|
||||
constexpr lvalue_rvalue_adl_swappable(int value) noexcept : value_(value) {}
|
||||
|
||||
constexpr
|
||||
lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr
|
||||
lvalue_rvalue_adl_swappable(lvalue_rvalue_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr lvalue_rvalue_adl_swappable&
|
||||
operator=(lvalue_rvalue_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(lvalue_rvalue_adl_swappable& x,
|
||||
lvalue_rvalue_adl_swappable&& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(lvalue_rvalue_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
lvalue_rvalue_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class rvalue_lvalue_adl_swappable {
|
||||
public:
|
||||
rvalue_lvalue_adl_swappable() = default;
|
||||
|
||||
constexpr rvalue_lvalue_adl_swappable(int value) noexcept : value_(value) {}
|
||||
|
||||
constexpr
|
||||
rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr
|
||||
rvalue_lvalue_adl_swappable(rvalue_lvalue_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr rvalue_lvalue_adl_swappable&
|
||||
operator=(rvalue_lvalue_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(rvalue_lvalue_adl_swappable&& x,
|
||||
rvalue_lvalue_adl_swappable& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(rvalue_lvalue_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
rvalue_lvalue_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class rvalue_adl_swappable {
|
||||
public:
|
||||
rvalue_adl_swappable() = default;
|
||||
|
||||
constexpr rvalue_adl_swappable(int value) noexcept : value_(value) {}
|
||||
|
||||
constexpr rvalue_adl_swappable(rvalue_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr rvalue_adl_swappable(rvalue_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr rvalue_adl_swappable&
|
||||
operator=(rvalue_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(rvalue_adl_swappable&& x,
|
||||
rvalue_adl_swappable&& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool operator==(rvalue_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
rvalue_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class non_move_constructible_adl_swappable {
|
||||
public:
|
||||
non_move_constructible_adl_swappable() = default;
|
||||
|
||||
constexpr non_move_constructible_adl_swappable(int value) noexcept
|
||||
: value_(value) {}
|
||||
|
||||
constexpr non_move_constructible_adl_swappable(
|
||||
non_move_constructible_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr non_move_constructible_adl_swappable(
|
||||
non_move_constructible_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr non_move_constructible_adl_swappable&
|
||||
operator=(non_move_constructible_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(non_move_constructible_adl_swappable& x,
|
||||
non_move_constructible_adl_swappable& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(non_move_constructible_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
non_move_constructible_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class non_move_assignable_adl_swappable {
|
||||
public:
|
||||
non_move_assignable_adl_swappable() = default;
|
||||
|
||||
constexpr non_move_assignable_adl_swappable(int value) noexcept
|
||||
: value_(value) {}
|
||||
|
||||
non_move_assignable_adl_swappable(non_move_assignable_adl_swappable&& other) =
|
||||
delete;
|
||||
|
||||
constexpr non_move_assignable_adl_swappable(
|
||||
non_move_assignable_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr non_move_assignable_adl_swappable&
|
||||
operator=(non_move_assignable_adl_swappable&& other) noexcept = delete;
|
||||
|
||||
constexpr friend void swap(non_move_assignable_adl_swappable& x,
|
||||
non_move_assignable_adl_swappable& y) noexcept {
|
||||
std::ranges::swap(x.value_, y.value_);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(non_move_assignable_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
non_move_assignable_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
class throwable_adl_swappable {
|
||||
public:
|
||||
throwable_adl_swappable() = default;
|
||||
|
||||
constexpr throwable_adl_swappable(int value) noexcept : value_(value) {}
|
||||
|
||||
constexpr throwable_adl_swappable(throwable_adl_swappable&& other) noexcept
|
||||
: value_(std::move(other.value_)),
|
||||
this_(this) {}
|
||||
|
||||
constexpr
|
||||
throwable_adl_swappable(throwable_adl_swappable const& other) noexcept
|
||||
: value_(other.value_),
|
||||
this_(this) {}
|
||||
|
||||
constexpr throwable_adl_swappable&
|
||||
operator=(throwable_adl_swappable other) noexcept {
|
||||
value_ = other.value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr friend void swap(throwable_adl_swappable& X,
|
||||
throwable_adl_swappable& Y) noexcept(false) {
|
||||
std::ranges::swap(X.value_, Y.value_);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(throwable_adl_swappable const& other) const noexcept {
|
||||
return value_ == other.value_ && this_ == this && other.this_ == &other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value_{};
|
||||
throwable_adl_swappable* this_ = this;
|
||||
};
|
||||
|
||||
#endif // TEST_STD_CONCEPTS_LANG_SWAPPABLE_H
|
|
@ -0,0 +1,295 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class T>
|
||||
// concept swappable = // see below
|
||||
|
||||
#include <concepts>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "moveconstructible.h"
|
||||
#include "swappable.h"
|
||||
|
||||
template <class T>
|
||||
struct expected {
|
||||
T x;
|
||||
T y;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
// Checks [concept.swappable]/2.1
|
||||
template <class T, class U>
|
||||
requires std::same_as<std::remove_cvref_t<T>, std::remove_cvref_t<U> > &&
|
||||
std::swappable<std::remove_cvref_t<T> >
|
||||
constexpr bool check_swap_21(T&& x, U&& y) {
|
||||
expected<std::remove_cvref_t<T> > const e{y, x};
|
||||
std::ranges::swap(std::forward<T>(x), std::forward<U>(y));
|
||||
return x == e.x && y == e.y;
|
||||
}
|
||||
|
||||
// Checks [concept.swappable]/2.2
|
||||
template <std::swappable T, std::size_t N>
|
||||
constexpr bool check_swap_22(T (&x)[N], T (&y)[N]) {
|
||||
expected<T[N]> e;
|
||||
std::copy(y, y + N, e.x);
|
||||
std::copy(x, x + N, e.y);
|
||||
|
||||
std::ranges::swap(x, y);
|
||||
return std::equal(x, x + N, e.x, e.x + N) &&
|
||||
std::equal(y, y + N, e.y, e.y + N);
|
||||
}
|
||||
|
||||
// Checks [concept.swappable]/2.3
|
||||
template <std::swappable T>
|
||||
requires std::copy_constructible<std::remove_cvref_t<T> >
|
||||
constexpr bool check_swap_23(T x, T y) {
|
||||
expected<std::remove_cvref_t<T> > const e{y, x};
|
||||
std::ranges::swap(x, y);
|
||||
return x == e.x && y == e.y;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
constexpr bool check_lvalue_adl_swappable() {
|
||||
auto x = lvalue_adl_swappable(0);
|
||||
auto y = lvalue_adl_swappable(1);
|
||||
constexpr auto is_noexcept = noexcept(std::ranges::swap(x, y));
|
||||
return check_swap_21(x, y) && is_noexcept;
|
||||
}
|
||||
static_assert(check_lvalue_adl_swappable());
|
||||
|
||||
constexpr bool check_rvalue_adl_swappable() {
|
||||
constexpr auto is_noexcept = noexcept(
|
||||
std::ranges::swap(rvalue_adl_swappable(0), rvalue_adl_swappable(1)));
|
||||
return check_swap_21(rvalue_adl_swappable(0), rvalue_adl_swappable(1)) &&
|
||||
is_noexcept;
|
||||
}
|
||||
static_assert(check_rvalue_adl_swappable());
|
||||
|
||||
constexpr bool check_lvalue_rvalue_adl_swappable() {
|
||||
auto x = lvalue_rvalue_adl_swappable(0);
|
||||
constexpr auto is_noexcept =
|
||||
noexcept(std::ranges::swap(x, lvalue_rvalue_adl_swappable(1)));
|
||||
return check_swap_21(x, lvalue_rvalue_adl_swappable(1)) && is_noexcept;
|
||||
}
|
||||
static_assert(check_lvalue_rvalue_adl_swappable());
|
||||
|
||||
constexpr bool check_rvalue_lvalue_adl_swappable() {
|
||||
auto x = rvalue_lvalue_adl_swappable(0);
|
||||
constexpr auto is_noexcept =
|
||||
noexcept(std::ranges::swap(rvalue_lvalue_adl_swappable(1), x));
|
||||
return check_swap_21(rvalue_lvalue_adl_swappable(1), x) && is_noexcept;
|
||||
}
|
||||
static_assert(check_rvalue_lvalue_adl_swappable());
|
||||
|
||||
constexpr bool check_throwable_swappable() {
|
||||
auto x = throwable_adl_swappable{0};
|
||||
auto y = throwable_adl_swappable{1};
|
||||
constexpr auto not_noexcept = !noexcept(std::ranges::swap(x, y));
|
||||
return check_swap_21(x, y) && not_noexcept;
|
||||
}
|
||||
static_assert(check_throwable_swappable());
|
||||
|
||||
constexpr bool check_non_move_constructible_adl_swappable() {
|
||||
auto x = non_move_constructible_adl_swappable{0};
|
||||
auto y = non_move_constructible_adl_swappable{1};
|
||||
constexpr auto is_noexcept = noexcept(std::ranges::swap(x, y));
|
||||
return check_swap_21(x, y) && is_noexcept;
|
||||
}
|
||||
static_assert(check_non_move_constructible_adl_swappable());
|
||||
|
||||
constexpr bool check_non_move_assignable_adl_swappable() {
|
||||
auto x = non_move_assignable_adl_swappable{0};
|
||||
auto y = non_move_assignable_adl_swappable{1};
|
||||
return check_swap_21(x, y) && noexcept(std::ranges::swap(x, y));
|
||||
}
|
||||
static_assert(check_non_move_assignable_adl_swappable());
|
||||
|
||||
namespace swappable_namespace {
|
||||
enum unscoped { hello, world };
|
||||
void swap(unscoped&, unscoped&);
|
||||
|
||||
enum class scoped { hello, world };
|
||||
void swap(scoped&, scoped&);
|
||||
} // namespace swappable_namespace
|
||||
|
||||
static_assert(std::swappable<swappable_namespace::unscoped>);
|
||||
static_assert(std::swappable<swappable_namespace::scoped>);
|
||||
|
||||
constexpr bool check_swap_arrays() {
|
||||
int x[] = {0, 1, 2, 3, 4};
|
||||
int y[] = {5, 6, 7, 8, 9};
|
||||
return check_swap_22(x, y) && noexcept(std::ranges::swap(x, y));
|
||||
}
|
||||
static_assert(check_swap_arrays());
|
||||
|
||||
constexpr bool check_lvalue_adl_swappable_arrays() {
|
||||
lvalue_adl_swappable x[] = {{0}, {1}, {2}, {3}};
|
||||
lvalue_adl_swappable y[] = {{4}, {5}, {6}, {7}};
|
||||
return check_swap_22(x, y) && noexcept(std::ranges::swap(x, y));
|
||||
}
|
||||
static_assert(check_lvalue_adl_swappable_arrays());
|
||||
|
||||
constexpr bool check_throwable_adl_swappable_arrays() {
|
||||
throwable_adl_swappable x[] = {{0}, {1}, {2}, {3}};
|
||||
throwable_adl_swappable y[] = {{4}, {5}, {6}, {7}};
|
||||
return check_swap_22(x, y) && !noexcept(std::ranges::swap(x, y));
|
||||
}
|
||||
static_assert(check_throwable_adl_swappable_arrays());
|
||||
|
||||
inline auto global_x = 0;
|
||||
static_assert(check_swap_23(0, 0) &&
|
||||
noexcept(std::ranges::swap(global_x, global_x)));
|
||||
static_assert(check_swap_23(0, 1) &&
|
||||
noexcept(std::ranges::swap(global_x, global_x)));
|
||||
static_assert(check_swap_23(1, 0) &&
|
||||
noexcept(std::ranges::swap(global_x, global_x)));
|
||||
|
||||
constexpr bool check_swappable_references() {
|
||||
int x = 42;
|
||||
int y = 64;
|
||||
return check_swap_23<int&>(x, y) && noexcept(std::ranges::swap(x, y));
|
||||
}
|
||||
static_assert(check_swappable_references());
|
||||
|
||||
constexpr bool check_swappable_pointers() {
|
||||
char const* x = "hello";
|
||||
return check_swap_23<char const*>(x, nullptr) &&
|
||||
noexcept(std::ranges::swap(x, x));
|
||||
}
|
||||
static_assert(check_swappable_pointers());
|
||||
|
||||
namespace union_swap {
|
||||
union adl_swappable {
|
||||
int x;
|
||||
double y;
|
||||
};
|
||||
|
||||
void swap(adl_swappable&, adl_swappable&);
|
||||
void swap(adl_swappable&&, adl_swappable&&);
|
||||
}; // namespace union_swap
|
||||
static_assert(std::swappable<union_swap::adl_swappable>);
|
||||
static_assert(std::swappable<union_swap::adl_swappable&>);
|
||||
static_assert(std::swappable<union_swap::adl_swappable&&>);
|
||||
|
||||
// All tests for std::swappable<T> are implicitly confirmed by `check_swap`, so we only need to
|
||||
// sanity check for a few positive cases.
|
||||
static_assert(std::swappable<int volatile&>);
|
||||
static_assert(std::swappable<int&&>);
|
||||
static_assert(std::swappable<int (*)()>);
|
||||
static_assert(std::swappable<int rvalue_adl_swappable::*>);
|
||||
static_assert(std::swappable<int (rvalue_adl_swappable::*)()>);
|
||||
static_assert(std::swappable<std::unique_ptr<int> >);
|
||||
|
||||
static_assert(!std::swappable<void>);
|
||||
static_assert(!std::swappable<int const>);
|
||||
static_assert(!std::swappable<int const&>);
|
||||
static_assert(!std::swappable<int const&&>);
|
||||
static_assert(!std::swappable<int const volatile>);
|
||||
static_assert(!std::swappable<int const volatile&>);
|
||||
static_assert(!std::swappable<int const volatile&&>);
|
||||
static_assert(!std::swappable<int (&)()>);
|
||||
static_assert(!std::swappable<DeletedMoveCtor>);
|
||||
static_assert(!std::swappable<ImplicitlyDeletedMoveCtor>);
|
||||
static_assert(!std::swappable<DeletedMoveAssign>);
|
||||
static_assert(!std::swappable<ImplicitlyDeletedMoveAssign>);
|
||||
static_assert(!std::swappable<NonMovable>);
|
||||
static_assert(!std::swappable<DerivedFromNonMovable>);
|
||||
static_assert(!std::swappable<HasANonMovable>);
|
||||
|
||||
using swap_type = std::remove_const_t<decltype(std::ranges::swap)>;
|
||||
static_assert(std::default_initializable<swap_type>);
|
||||
static_assert(std::move_constructible<swap_type>);
|
||||
static_assert(std::copy_constructible<swap_type>);
|
||||
static_assert(std::assignable_from<swap_type&, swap_type>);
|
||||
static_assert(std::assignable_from<swap_type&, swap_type&>);
|
||||
static_assert(std::assignable_from<swap_type&, swap_type const&>);
|
||||
static_assert(std::assignable_from<swap_type&, swap_type const>);
|
||||
static_assert(std::swappable<swap_type>);
|
||||
|
||||
template <bool is_noexcept, std::swappable T>
|
||||
void check_swap(expected<T> const& e) {
|
||||
auto a = e.y;
|
||||
auto b = e.x;
|
||||
|
||||
std::ranges::swap(a, b);
|
||||
assert(a == e.x);
|
||||
assert(b == e.y);
|
||||
|
||||
std::ranges::swap(a, b);
|
||||
assert(a == e.y);
|
||||
assert(b == e.x);
|
||||
|
||||
static_assert(noexcept(std::ranges::swap(a, b)) == is_noexcept);
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
{
|
||||
auto const e = expected<std::deque<int> >{
|
||||
.x = {6, 7, 8, 9},
|
||||
.y = {0, 1, 2, 3, 4, 5},
|
||||
};
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::map<int, std::string> >{
|
||||
.x = {{0, "whole"}, {1, "cashews"}},
|
||||
.y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},
|
||||
};
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::string>{
|
||||
.x = "hello there",
|
||||
.y = "general kenobi",
|
||||
};
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::optional<lvalue_adl_swappable> >{
|
||||
.x = {10},
|
||||
.y = {20},
|
||||
};
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::optional<throwable_adl_swappable> >{
|
||||
.x = {10},
|
||||
.y = {20},
|
||||
};
|
||||
check_swap</*is_noexcept=*/false>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::unordered_map<int, std::string> >{
|
||||
.x = {{0, "whole"}, {1, "cashews"}},
|
||||
.y = {{-1, "roasted"}, {2, "&"}, {-3, "salted"}},
|
||||
};
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
{
|
||||
auto const e = expected<std::vector<int> >{
|
||||
.x = {0, 1, 2, 3, 4, 5},
|
||||
.y = {6, 7, 8, 9},
|
||||
};
|
||||
|
||||
check_swap</*is_noexcept=*/true>(e);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,647 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class T, class U>
|
||||
// concept swappable_with = // see below
|
||||
|
||||
#include <concepts>
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "moveconstructible.h"
|
||||
#include "swappable.h"
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool check_swappable_with_impl() {
|
||||
static_assert(std::swappable_with<T, U> == std::swappable_with<U, T>);
|
||||
return std::swappable_with<T, U>;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool check_swappable_with() {
|
||||
static_assert(!check_swappable_with_impl<T, U>());
|
||||
static_assert(!check_swappable_with_impl<T, U const>());
|
||||
static_assert(!check_swappable_with_impl<T const, U>());
|
||||
static_assert(!check_swappable_with_impl<T const, U const>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T, U&>());
|
||||
static_assert(!check_swappable_with_impl<T, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U const volatile&>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&, U>());
|
||||
static_assert(!check_swappable_with_impl<T&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U const>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T&, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U volatile&>());
|
||||
static_assert(
|
||||
!check_swappable_with_impl<T const volatile&, U const volatile&>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const, U const volatile&&>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&&, U>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U const>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U const>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&, U volatile&&>());
|
||||
static_assert(
|
||||
!check_swappable_with_impl<T const volatile&, U const volatile&&>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U const volatile&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U const&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U volatile&>());
|
||||
static_assert(
|
||||
!check_swappable_with_impl<T const volatile&&, U const volatile&>());
|
||||
|
||||
static_assert(!check_swappable_with_impl<T&&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T&&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const&&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T volatile&&, U const volatile&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U const&&>());
|
||||
static_assert(!check_swappable_with_impl<T const volatile&&, U volatile&&>());
|
||||
static_assert(
|
||||
!check_swappable_with_impl<T const volatile&&, U const volatile&&>());
|
||||
return check_swappable_with_impl<T&, U&>();
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool check_swappable_with_including_lvalue_ref_to_volatile() {
|
||||
constexpr auto result = check_swappable_with<T, U>();
|
||||
static_assert(check_swappable_with_impl<T volatile&, U volatile&>() ==
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace fundamental {
|
||||
static_assert(
|
||||
check_swappable_with_including_lvalue_ref_to_volatile<int, int>());
|
||||
static_assert(
|
||||
check_swappable_with_including_lvalue_ref_to_volatile<double, double>());
|
||||
static_assert(
|
||||
!check_swappable_with_including_lvalue_ref_to_volatile<int, double>());
|
||||
|
||||
static_assert(
|
||||
check_swappable_with_including_lvalue_ref_to_volatile<int*, int*>());
|
||||
static_assert(
|
||||
!check_swappable_with_including_lvalue_ref_to_volatile<int, int*>());
|
||||
static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
|
||||
int (*)(), int (*)()>());
|
||||
static_assert(
|
||||
!check_swappable_with_including_lvalue_ref_to_volatile<int, int (*)()>());
|
||||
|
||||
struct S {};
|
||||
static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<int, S>());
|
||||
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::*)(), 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<int[5], int[5]>());
|
||||
static_assert(
|
||||
!check_swappable_with_including_lvalue_ref_to_volatile<int[5], int[6]>());
|
||||
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<int[5][6],
|
||||
int[5]>());
|
||||
static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<int[5][6],
|
||||
int[6]>());
|
||||
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<void, void>());
|
||||
static_assert(!check_swappable_with_impl<int, void>());
|
||||
static_assert(!check_swappable_with_impl<int&, void>());
|
||||
static_assert(!check_swappable_with_impl<void, int>());
|
||||
static_assert(!check_swappable_with_impl<void, int&>());
|
||||
static_assert(!check_swappable_with_impl<int, int()>());
|
||||
static_assert(!check_swappable_with_impl<int, int (&)()>());
|
||||
} // namespace fundamental
|
||||
|
||||
namespace adl {
|
||||
static_assert(
|
||||
check_swappable_with<lvalue_adl_swappable, lvalue_adl_swappable>());
|
||||
static_assert(check_swappable_with<lvalue_rvalue_adl_swappable,
|
||||
lvalue_rvalue_adl_swappable>());
|
||||
static_assert(check_swappable_with<rvalue_lvalue_adl_swappable,
|
||||
rvalue_lvalue_adl_swappable>());
|
||||
static_assert(
|
||||
check_swappable_with_impl<rvalue_adl_swappable, rvalue_adl_swappable>());
|
||||
static_assert(!check_swappable_with_impl<lvalue_rvalue_adl_swappable&,
|
||||
lvalue_rvalue_adl_swappable&&>());
|
||||
|
||||
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<s1, no_common_reference_with_s1>());
|
||||
|
||||
struct one_way_swappable_with_s1 {
|
||||
friend void swap(s1&, one_way_swappable_with_s1&);
|
||||
operator s1();
|
||||
};
|
||||
static_assert(std::common_reference_with<one_way_swappable_with_s1, s1>);
|
||||
static_assert(!check_swappable_with<one_way_swappable_with_s1, s1>());
|
||||
|
||||
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<one_way_swappable_with_s1_other_way, s1>);
|
||||
static_assert(!check_swappable_with<one_way_swappable_with_s1_other_way, s1>());
|
||||
|
||||
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<can_swap_with_s1_but_not_swappable, s1>);
|
||||
static_assert(!std::swappable<can_swap_with_s1_but_not_swappable>);
|
||||
static_assert(
|
||||
!check_swappable_with<can_swap_with_s1_but_not_swappable&, s1&>());
|
||||
|
||||
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<swappable_with_s1, s1>());
|
||||
|
||||
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<swappable_with_const_s1_but_not_swappable const&>);
|
||||
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<swappable_with_volatile_s1_but_not_swappable volatile&>);
|
||||
static_assert(
|
||||
!std::swappable_with<swappable_with_volatile_s1_but_not_swappable volatile&,
|
||||
s1 volatile&>);
|
||||
|
||||
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<swappable_with_cv_s1_but_not_swappable const volatile&>);
|
||||
static_assert(
|
||||
!std::swappable_with<swappable_with_cv_s1_but_not_swappable const volatile&,
|
||||
s1 const volatile&>);
|
||||
|
||||
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<swappable_with_const_s2 const&, s2 const&>);
|
||||
|
||||
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<swappable_with_volatile_s2 volatile&, s2 volatile&>);
|
||||
|
||||
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<swappable_with_cv_s2 const volatile&,
|
||||
s2 const volatile&>);
|
||||
|
||||
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<swappable_with_rvalue_ref_to_s1_but_not_swappable const&&>);
|
||||
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<swappable_with_rvalue_ref_to_s3&&, s3&&>);
|
||||
|
||||
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<swappable_with_rvalue_ref_to_const_s3 const&&,
|
||||
s3 const&&>);
|
||||
|
||||
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<swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
|
||||
s3 volatile&&>);
|
||||
|
||||
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<swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
|
||||
s3 const volatile&&>);
|
||||
|
||||
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<union_swap::adl_swappable, union_swap::adl_swappable>);
|
||||
static_assert(std::swappable_with<union_swap::adl_swappable&,
|
||||
union_swap::adl_swappable&>);
|
||||
static_assert(std::swappable_with<union_swap::adl_swappable&&,
|
||||
union_swap::adl_swappable&&>);
|
||||
static_assert(std::swappable_with<union_swap::adl_swappable&, int&>);
|
||||
} // namespace adl
|
||||
|
||||
namespace standard_types {
|
||||
static_assert(
|
||||
check_swappable_with<std::array<int, 10>, std::array<int, 10> >());
|
||||
static_assert(
|
||||
!check_swappable_with<std::array<int, 10>, std::array<double, 10> >());
|
||||
static_assert(check_swappable_with<std::deque<int>, std::deque<int> >());
|
||||
static_assert(!check_swappable_with<std::deque<int>, std::vector<int> >());
|
||||
static_assert(
|
||||
check_swappable_with<std::forward_list<int>, std::forward_list<int> >());
|
||||
static_assert(
|
||||
!check_swappable_with<std::forward_list<int>, std::vector<int> >());
|
||||
static_assert(check_swappable_with<std::list<int>, std::list<int> >());
|
||||
static_assert(!check_swappable_with<std::list<int>, std::vector<int> >());
|
||||
|
||||
static_assert(
|
||||
check_swappable_with<std::map<int, void*>, std::map<int, void*> >());
|
||||
static_assert(!check_swappable_with<std::map<int, void*>, std::vector<int> >());
|
||||
static_assert(check_swappable_with<std::optional<std::vector<int> >,
|
||||
std::optional<std::vector<int> > >());
|
||||
static_assert(!check_swappable_with<std::optional<std::vector<int> >,
|
||||
std::vector<int> >());
|
||||
static_assert(check_swappable_with<std::vector<int>, std::vector<int> >());
|
||||
static_assert(!check_swappable_with<std::vector<int>, int>());
|
||||
} // namespace standard_types
|
||||
|
||||
namespace types_with_purpose {
|
||||
static_assert(!check_swappable_with<DeletedMoveCtor, DeletedMoveCtor>());
|
||||
static_assert(!check_swappable_with<ImplicitlyDeletedMoveCtor,
|
||||
ImplicitlyDeletedMoveCtor>());
|
||||
static_assert(!check_swappable_with<DeletedMoveAssign, DeletedMoveAssign>());
|
||||
static_assert(!check_swappable_with<ImplicitlyDeletedMoveAssign,
|
||||
ImplicitlyDeletedMoveAssign>());
|
||||
static_assert(!check_swappable_with<NonMovable, NonMovable>());
|
||||
static_assert(
|
||||
!check_swappable_with<DerivedFromNonMovable, DerivedFromNonMovable>());
|
||||
static_assert(!check_swappable_with<HasANonMovable, HasANonMovable>());
|
||||
} // namespace types_with_purpose
|
||||
|
||||
int main(int, char**) { return 0; }
|
Loading…
Reference in New Issue