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>;