template<class Derived, class Base>
concept DerivedFrom =
is_base_of_v<Base, Derived> &&
is_convertible_v<const volatile Derived*, const volatile Base*>;
template<class From, class To>
concept ConvertibleTo =
is_convertible_v<From, To> &&
requires(From (&f)()) {
static_cast<To>(f());
};
To test(From (&f)()) {
return f();
}
and let f be a function with no arguments and return type From
such that f() is equality-preserving.template<class T, class U>
concept CommonReference =
Same<common_reference_t<T, U>, common_reference_t<U, T>> &&
ConvertibleTo<T, common_reference_t<T, U>> &&
ConvertibleTo<U, common_reference_t<T, U>>;
template<class T, class U>
concept Common =
Same<common_type_t<T, U>, common_type_t<U, T>> &&
ConvertibleTo<T, common_type_t<T, U>> &&
ConvertibleTo<U, common_type_t<T, U>> &&
CommonReference<
add_lvalue_reference_t<const T>,
add_lvalue_reference_t<const U>> &&
CommonReference<
add_lvalue_reference_t<common_type_t<T, U>>,
common_reference_t<
add_lvalue_reference_t<const T>,
add_lvalue_reference_t<const U>>>;
template<class T>
concept Integral = is_integral_v<T>;
template<class T>
concept SignedIntegral = Integral<T> && is_signed_v<T>;
template<class T>
concept UnsignedIntegral = Integral<T> && !SignedIntegral<T>;
template<class LHS, class RHS>
concept Assignable =
is_lvalue_reference_v<LHS> &&
CommonReference<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&> &&
requires(LHS lhs, RHS&& rhs) {
lhs = std::forward<RHS>(rhs);
requires Same<decltype(lhs = std::forward<RHS>(rhs)), LHS>;
};
template<class T>
concept Swappable = is_swappable_v<T>;
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>;
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
#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);
}template<class T>
concept Destructible = is_nothrow_destructible_v<T>;
template<class T, class... Args>
concept Constructible = Destructible<T> && is_constructible_v<T, Args...>;
template<class T>
concept DefaultConstructible = Constructible<T>;
template<class T>
concept MoveConstructible = Constructible<T, T> && ConvertibleTo<T, T>;
template<class T>
concept CopyConstructible =
MoveConstructible<T> &&
Constructible<T, T&> && ConvertibleTo<T&, T> &&
Constructible<T, const T&> && ConvertibleTo<const T&, T> &&
Constructible<T, const T> && ConvertibleTo<const T, T>;