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 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>> &&
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>;
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; requires ConvertibleTo<decltype(!b1), bool>;
b1 && a; requires Same<decltype(b1 && a), bool>;
b1 || a; requires Same<decltype(b1 || a), bool>;
b1 && b2; requires Same<decltype(b1 && b2), bool>;
a && b2; requires Same<decltype( a && b2), bool>;
b1 || b2; requires Same<decltype(b1 || b2), bool>;
a || b2; requires Same<decltype( a || b2), bool>;
b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
a == b2; requires ConvertibleTo<decltype( a == b2), bool>;
b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
a != b2; requires ConvertibleTo<decltype( a != b2), 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; requires Boolean<decltype(t == u)>;
t != u; requires Boolean<decltype(t != u)>;
u == t; requires Boolean<decltype(u == t)>;
u != t; requires Boolean<decltype(u != t)>;
};
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; requires Boolean<decltype(a < b)>;
a > b; requires Boolean<decltype(a > b)>;
a <= b; requires Boolean<decltype(a <= b)>;
a >= b; requires Boolean<decltype(a >= b)>;
};
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; requires Boolean<decltype(t < u)>;
t > u; requires Boolean<decltype(t > u)>;
t <= u; requires Boolean<decltype(t <= u)>;
t >= u; requires Boolean<decltype(t >= u)>;
u < t; requires Boolean<decltype(u < t)>;
u > t; requires Boolean<decltype(u > t)>;
u <= t; requires Boolean<decltype(u <= t)>;
u >= t; requires Boolean<decltype(u >= t)>;
};
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> &&
CommonReference<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
Predicate<R,
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>,
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>> &&
Predicate<R, T, U> && Predicate<R, U, T>;
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>
template<class R, class T, class U>
concept StrictWeakOrder = Relation<R, T, U>;