template<class T> concept C = requires(T a, T b, const T c, const T d) { c == d; // #1 a = std::move(b); // #2 a = c; // #3 };
c == b;
c == std::move(d); c == std::move(b);
std::move(c) == d; std::move(c) == b;
std::move(c) == std::move(d); std::move(c) == std::move(b);
a == d; a == b;
a == std::move(d); a == std::move(b);
std::move(a) == d; std::move(a) == b;
std::move(a) == std::move(d); std::move(a) == std::move(b);
had been declared as well.struct T { bool operator==(const T&) const { return true; } bool operator==(T&) = delete; };
namespace std { // [concepts.lang], language-related concepts // [concept.same], concept Same template<class T, class U> concept Same = see below; // [concept.derivedfrom], concept DerivedFrom template<class Derived, class Base> concept DerivedFrom = see below; // [concept.convertibleto], concept ConvertibleTo template<class From, class To> concept ConvertibleTo = see below; // [concept.commonref], concept CommonReference template<class T, class U> concept CommonReference = see below; // [concept.common], concept Common template<class T, class U> concept Common = see below; // [concepts.integral], integral concepts template<class T> concept Integral = see below; template<class T> concept SignedIntegral = see below; template<class T> concept UnsignedIntegral = see below; // [concept.assignable], concept Assignable template<class LHS, class RHS> concept Assignable = see below; // [concept.swappable], concept Swappable namespace ranges { inline namespace unspecified { inline constexpr unspecified swap = unspecified; } } template<class T> concept Swappable = see below; template<class T, class U> concept SwappableWith = see below; // [concept.destructible], concept Destructible template<class T> concept Destructible = see below; // [concept.constructible], concept Constructible template<class T, class... Args> concept Constructible = see below; // [concept.defaultconstructible], concept DefaultConstructible template<class T> concept DefaultConstructible = see below; // [concept.moveconstructible], concept MoveConstructible template<class T> concept MoveConstructible = see below; // [concept.copyconstructible], concept CopyConstructible template<class T> concept CopyConstructible = see below; // [concepts.compare], comparison concepts // [concept.boolean], concept Boolean template<class B> concept Boolean = see below; // [concept.equalitycomparable], concept EqualityComparable template<class T> concept EqualityComparable = see below; template<class T, class U> concept EqualityComparableWith = see below; // [concept.stricttotallyordered], concept StrictTotallyOrdered template<class T> concept StrictTotallyOrdered = see below; template<class T, class U> concept StrictTotallyOrderedWith = see below; // [concepts.object], object concepts template<class T> concept Movable = see below; template<class T> concept Copyable = see below; template<class T> concept Semiregular = see below; template<class T> concept Regular = see below; // [concepts.callable], callable concepts // [concept.invocable], concept Invocable template<class F, class... Args> concept Invocable = see below; // [concept.regularinvocable], concept RegularInvocable template<class F, class... Args> concept RegularInvocable = see below; // [concept.predicate], concept Predicate template<class F, class... Args> concept Predicate = see below; // [concept.relation], concept Relation template<class R, class T, class U> concept Relation = see below; // [concept.strictweakorder], concept StrictWeakOrder template<class R, class T, class U> concept StrictWeakOrder = see below; }
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>> &&
requires {
static_cast<common_type_t<T, U>>(declval<T>());
static_cast<common_type_t<T, U>>(declval<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) } -> Same<LHS>;
};
template<class T> void swap(T&, T&) = delete; template<class T, size_t N> void swap(T(&)[N], T(&)[N]) = delete;and does not include a declaration of ranges::swap.
T t1(std::move(E1)); T t2(std::move(E2));
template<class T>
concept Swappable = requires(T& a, T& b) { ranges::swap(a, b); };
template<class T, class U>
concept SwappableWith =
CommonReference<const remove_reference_t<T>&, const remove_reference_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));
};
#include <cassert> #include <concepts> #include <utility> namespace ranges = std::ranges; template<class T, std::SwappableWith<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 proxy(A& a) { return Proxy{ &a }; } void swap(A& x, Proxy p) { ranges::swap(x.m, p.a->m); } void swap(Proxy p, A& x) { swap(x, p); } // satisfy symmetry requirement } 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>;
template<class B>
concept Boolean =
Movable<remove_cvref_t<B>> && // (see [concepts.object])
requires(const remove_reference_t<B>& b1,
const remove_reference_t<B>& b2, const bool a) {
requires ConvertibleTo<const remove_reference_t<B>&, bool>;
{ !b1 } -> ConvertibleTo<bool>;
{ b1 && a } -> Same<bool>;
{ b1 || a } -> Same<bool>;
{ b1 && b2 } -> Same<bool>;
{ a && b2 } -> Same<bool>;
{ b1 || b2 } -> Same<bool>;
{ a || b2 } -> Same<bool>;
{ b1 == b2 } -> ConvertibleTo<bool>;
{ b1 == a } -> ConvertibleTo<bool>;
{ a == b2 } -> ConvertibleTo<bool>;
{ b1 != b2 } -> ConvertibleTo<bool>;
{ b1 != a } -> ConvertibleTo<bool>;
{ a != b2 } -> ConvertibleTo<bool>;
};
template<class T, class U>
concept weakly-equality-comparable-with = // exposition only
requires(const remove_reference_t<T>& t,
const remove_reference_t<U>& u) {
{ t == u } -> Boolean;
{ t != u } -> Boolean;
{ u == t } -> Boolean;
{ u != t } -> Boolean;
};
template<class T>
concept EqualityComparable = weakly-equality-comparable-with<T, T>;
template<class T, class U>
concept EqualityComparableWith =
EqualityComparable<T> && EqualityComparable<U> &&
CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
EqualityComparable<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
weakly-equality-comparable-with<T, U>;
template<class T>
concept StrictTotallyOrdered =
EqualityComparable<T> &&
requires(const remove_reference_t<T>& a,
const remove_reference_t<T>& b) {
{ a < b } -> Boolean;
{ a > b } -> Boolean;
{ a <= b } -> Boolean;
{ a >= b } -> Boolean;
};
template<class T, class U>
concept StrictTotallyOrderedWith =
StrictTotallyOrdered<T> && StrictTotallyOrdered<U> &&
CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
StrictTotallyOrdered<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
EqualityComparableWith<T, U> &&
requires(const remove_reference_t<T>& t,
const remove_reference_t<U>& u) {
{ t < u } -> Boolean;
{ t > u } -> Boolean;
{ t <= u } -> Boolean;
{ t >= u } -> Boolean;
{ u < t } -> Boolean;
{ u > t } -> Boolean;
{ u <= t } -> Boolean;
{ u >= t } -> Boolean;
};
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>StrictTotallyOrderedWith<T, U> is satisfied only if
template<class T>
concept Movable = is_object_v<T> && MoveConstructible<T> && Assignable<T&, T> && Swappable<T>;
template<class T>
concept Copyable = CopyConstructible<T> && Movable<T> && Assignable<T&, const T&>;
template<class T>
concept Semiregular = Copyable<T> && DefaultConstructible<T>;
template<class T>
concept Regular = Semiregular<T> && EqualityComparable<T>;
template<class F, class... Args>
concept Invocable = requires(F&& f, Args&&... args) {
invoke(std::forward<F>(f), std::forward<Args>(args)...); // not required to be equality-preserving
};
template<class F, class... Args>
concept RegularInvocable = Invocable<F, Args...>;
template<class F, class... Args>
concept Predicate = RegularInvocable<F, Args...> && Boolean<invoke_result_t<F, Args...>>;
template<class R, class T, class U>
concept Relation =
Predicate<R, T, T> && Predicate<R, U, U> &&
Predicate<R, T, U> && Predicate<R, U, T>;
template<class R, class T, class U>
concept StrictWeakOrder = Relation<R, T, U>;