Subclause | Header | |
Equality preservation | ||
Language-related concepts | <concepts> | |
Comparison concepts | ||
Object concepts | ||
Callable concepts |
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_as template<class T, class U> concept same_as = see below; // [concept.derived], concept derived_from template<class Derived, class Base> concept derived_from = see below; // [concept.convertible], concept convertible_to template<class From, class To> concept convertible_to = see below; // [concept.commonref], concept common_reference_with template<class T, class U> concept common_reference_with = see below; // [concept.common], concept common_with template<class T, class U> concept common_with = see below; // [concepts.arithmetic], arithmetic concepts template<class T> concept integral = see below; template<class T> concept signed_integral = see below; template<class T> concept unsigned_integral = see below; template<class T> concept floating_point = see below; // [concept.assignable], concept assignable_from template<class LHS, class RHS> concept assignable_from = 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 swappable_with = see below; // [concept.destructible], concept destructible template<class T> concept destructible = see below; // [concept.constructible], concept constructible_from template<class T, class... Args> concept constructible_from = see below; // [concept.default.init], concept default_initializable template<class T> concept default_initializable = see below; // [concept.moveconstructible], concept move_constructible template<class T> concept move_constructible = see below; // [concept.copyconstructible], concept copy_constructible template<class T> concept copy_constructible = see below; // [concepts.compare], comparison concepts // [concept.equalitycomparable], concept equality_comparable template<class T> concept equality_comparable = see below; template<class T, class U> concept equality_comparable_with = see below; // [concept.totallyordered], concept totally_ordered template<class T> concept totally_ordered = see below; template<class T, class U> concept totally_ordered_with = 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 regular_invocable template<class F, class... Args> concept regular_invocable = 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.equiv], concept equivalence_relation template<class R, class T, class U> concept equivalence_relation = see below; // [concept.strictweakorder], concept strict_weak_order template<class R, class T, class U> concept strict_weak_order = see below; }
template<class From, class To>
concept convertible_to =
is_convertible_v<From, To> &&
requires(add_rvalue_reference_t<From> (&f)()) {
static_cast<To>(f());
};
To test(FromR (&f)()) { return f(); }and let f be a function with no arguments and return type FromR such that f() is equality-preserving.
template<class T, class U>
concept common_reference_with =
same_as<common_reference_t<T, U>, common_reference_t<U, T>> &&
convertible_to<T, common_reference_t<T, U>> &&
convertible_to<U, common_reference_t<T, U>>;
template<class T, class U>
concept common_with =
same_as<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>());
} &&
common_reference_with<
add_lvalue_reference_t<const T>,
add_lvalue_reference_t<const U>> &&
common_reference_with<
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 signed_integral = integral<T> && is_signed_v<T>;
template<class T>
concept unsigned_integral = integral<T> && !signed_integral<T>;
template<class T>
concept floating_point = is_floating_point_v<T>;
template<class LHS, class RHS>
concept assignable_from =
is_lvalue_reference_v<LHS> &&
common_reference_with<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&> &&
requires(LHS lhs, RHS&& rhs) {
{ lhs = std::forward<RHS>(rhs) } -> same_as<LHS>;
};
template<class T> void swap(T&, T&) = delete;and does not include a declaration of ranges::swap.
T t1(std::move(E1)); T t2(std::move(E2));are constant subexpressions.
template<class T, class U>
concept swappable_with =
common_reference_with<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::swappable_with<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(A& a) : a{&a} {} friend void swap(Proxy x, Proxy y) { ranges::swap(*x.a, *y.a); } }; Proxy proxy(A& a) { return Proxy{ a }; } } 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>
inline constexpr bool is-default-initializable = see below; // exposition only
template<class T>
concept default_initializable = constructible_from<T> &&
requires { T{}; } &&
is-default-initializable<T>;
T t;is well-formed for some invented variable t; otherwise it is false.
namespace Z { template<class> struct C {}; template<class T> void operator&&(C<T> x, T y); template<class T> void operator||(C<type_identity_t<T>> x, T y); }the declaration of Z::operator&& contains one key parameter, C<T> x, and the declaration of Z::operator|| contains no key parameters.
template<class T>
concept boolean-testable = // exposition only
boolean-testable-impl<T> && requires (T&& t) {
{ !std::forward<T>(t) } -> boolean-testable-impl;
};
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-testable;
{ t != u } -> boolean-testable;
{ u == t } -> boolean-testable;
{ u != t } -> boolean-testable;
};
template<class T, class U>
concept equality_comparable_with =
equality_comparable<T> && equality_comparable<U> &&
common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&> &&
equality_comparable<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
weakly-equality-comparable-with<T, U>;
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>T and U model equality_comparable_with<T, U> only if bool(t == u) == bool(C(t) == C(u)).
template<class T>
concept totally_ordered =
equality_comparable<T> && partially-ordered-with<T, T>;
template<class T, class U>
concept totally_ordered_with =
totally_ordered<T> && totally_ordered<U> &&
equality_comparable_with<T, U> &&
totally_ordered<
common_reference_t<
const remove_reference_t<T>&,
const remove_reference_t<U>&>> &&
partially-ordered-with<T, U>;
common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>T and U model totally_ordered_with<T, U> only if
template<class T>
concept movable = is_object_v<T> && move_constructible<T> &&
assignable_from<T&, T> && swappable<T>;
template<class T>
concept copyable = copy_constructible<T> && movable<T> && assignable_from<T&, T&> &&
assignable_from<T&, const T&> && assignable_from<T&, const T>;
template<class T>
concept semiregular = copyable<T> && default_initializable<T>;
template<class T>
concept regular = semiregular<T> && equality_comparable<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
};