Difference between revisions of "cpp/concepts/equality comparable"
D41D8CD98F (Talk | contribs) |
m (+mark) |
||
(14 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
− | {{cpp/title|equality_comparable|equality_comparable_with}} | + | {{cpp/title|equality_comparable {{mark since c++20}}|equality_comparable_with {{mark since c++20}}}} |
{{cpp/concepts/navbar}} | {{cpp/concepts/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
{{dcl header|concepts}} | {{dcl header|concepts}} | ||
− | {{dcl|num=1|1= | + | {{dcl|num=1|since=c++20|1= |
− | template<class T, class U> | + | template< class T > |
− | + | concept equality_comparable = __WeaklyEqualityComparableWith<T, T>; | |
+ | }} | ||
+ | {{dcl|num=2|since=c++20|1= | ||
+ | template< class T, class U > | ||
+ | concept equality_comparable_with = | ||
+ | std::equality_comparable<T> && | ||
+ | std::equality_comparable<U> && | ||
+ | __ComparisonCommonTypeWith<T, U> && | ||
+ | std::equality_comparable< | ||
+ | std::common_reference_t< | ||
+ | const std::remove_reference_t<T>&, | ||
+ | const std::remove_reference_t<U>&>> && | ||
+ | __WeaklyEqualityComparableWith<T, U>; | ||
+ | }} | ||
+ | {{dcl h|Helper concepts}} | ||
+ | {{dcl|num=3|notes={{mark expos}}|1= | ||
+ | template< class T, class U > | ||
+ | concept __WeaklyEqualityComparableWith = | ||
requires(const std::remove_reference_t<T>& t, | requires(const std::remove_reference_t<T>& t, | ||
const std::remove_reference_t<U>& u) { | const std::remove_reference_t<U>& u) { | ||
− | + | { t == u } -> boolean-testable; | |
− | + | { t != u } -> boolean-testable; | |
− | + | { u == t } -> boolean-testable; | |
− | + | { u != t } -> boolean-testable; | |
}; | }; | ||
}} | }} | ||
− | {{dcl| | + | {{dcl rev begin|num=4}} |
− | template < class T > | + | {{dcl|until=c++23|notes={{mark expos}}|1= |
− | concept | + | template< class T, class U > |
+ | concept __ComparisonCommonTypeWith = | ||
+ | std::common_reference_with< | ||
+ | const std::remove_reference_t<T>&, | ||
+ | const std::remove_reference_t<U>&>; | ||
}} | }} | ||
− | {{dcl|since=c++ | + | {{dcl|since=c++23|notes={{mark expos}}|1= |
− | template <class T, class U> | + | template< class T, class U, class C = std::common_reference_t<const T&, const U&> > |
− | concept | + | concept _ComparisonCommonTypeWithImpl = |
− | + | std::same_as<std::common_reference_t<const T&, const U&>, | |
− | + | std::common_reference_t<const U&, const T&>> && | |
− | + | requires { | |
− | + | requires std::convertible_to<const T&, const C&> {{!!}} | |
− | + | std::convertible_to<T, const C&>; | |
− | + | requires std::convertible_to<const U&, const C&> {{!!}} | |
− | + | std::convertible_to<U, const C&>; | |
− | + | }; | |
− | + | template< class T, class U > | |
− | + | concept __ComparisonCommonTypeWith = | |
+ | _ComparisonCommonTypeWithImpl<std::remove_cvref_t<T>, std::remove_cvref_t<U>>; | ||
}} | }} | ||
+ | {{dcl rev end}} | ||
{{dcl end}} | {{dcl end}} | ||
− | @1@ The | + | @1@ The concept {{tt|std::equality_comparable}} specifies that the comparison operators {{tt|1===}} and {{tt|1=!=}} on {{tt|T}} reflects equality: {{tt|1===}} yields {{c|true}} if and only if the operands are equal. |
− | @2@ The concept {{tt| | + | @2@ The concept {{tt|std::equality_comparable_with}} specifies that the comparison operators {{tt|1===}} and {{tt|1=!=}} on (possibly mixed) {{tt|T}} and {{tt|U}} operands yield results consistent with equality. Comparing mixed operands yields results equivalent to comparing the operands converted to their common type. |
− | @3@ The concept {{tt| | + | @3@ The exposition-only concept {{tt|''__WeaklyEqualityComparableWith''}} specifies that an object of type {{tt|T}} and an object of type {{tt|U}} can be compared for equality with each other (in either order) using both {{tt|1===}} and {{tt|1=!=}}, and the results of the comparisons are consistent. |
− | === Semantic requirements === | + | @4@ The exposition-only concept {{tt|''__ComparisonCommonTypeWith''}} specifies that two types share a common type, and a const lvalue{{rev inl|since=c++23| or a non-const rvalue}} of either type is convertible to that common type. |
− | @1@ {{tt|__WeaklyEqualityComparableWith<T, U>}} is modeled only if given | + | |
+ | ===Semantic requirements=== | ||
+ | These concepts are modeled only if they are satisfied and all concepts they subsume are modeled. | ||
+ | |||
+ | In the following paragraphs, given an expression {{tt|E}} and a type {{tt|C}}, {{c|CONVERT_TO<C>(E)}} is defined as: | ||
+ | {{rrev multi|rev1= | ||
+ | * {{c|static_cast<C>(std::as_const(E))}}. | ||
+ | |since2=c++23|rev2= | ||
+ | * {{c|static_cast<const C&>(std::as_const(E))}} if that is a valid expression, | ||
+ | * {{c|static_cast<const C&>(std::move(E))}} otherwise. | ||
+ | }} | ||
+ | |||
+ | @1@ {{co|std::equality_comparable<T>}} is modeled only if, given objects {{tt|a}} and {{tt|b}} of type {{tt|T}}, {{c|1=bool(a == b)}} is {{c|true}} if and only if {{tt|a}} and {{tt|b}} are equal. Together with the requirement that {{c|1=a == b}} is [[cpp/concepts#Equality preservation|equality-preserving]], this implies that {{tt|1===}} is symmetric and transitive, and further that {{tt|1===}} is reflexive for all objects {{tt|a}} that are equal to at least one other object. | ||
+ | |||
+ | @2@ {{co|std::equality_comparable_with<T, U>}} is modeled only if, let | ||
+ | * {{tt|t}} and {{tt|t2}} be lvalues denoting distinct equal objects of types {{c|const std::remove_reference_t<T>}} and {{c|std::remove_cvref_t<T>}} respectively, | ||
+ | * {{tt|u}} and {{tt|u2}} be lvalues denoting distinct equal objects of types {{c|const std::remove_reference_t<U>}} and {{c|std::remove_cvref_t<U>}} respectively, | ||
+ | * {{tt|C}} be {{c|std::common_reference_t<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>}}, | ||
+ | the following expression is true: | ||
+ | * {{c|1=bool(t == u) == bool(CONVERT_TO<C>(t2) == CONVERT_TO<C>(u2))}}. | ||
+ | |||
+ | @3@ {{c|__WeaklyEqualityComparableWith<T, U>}} is modeled only if given | ||
* {{tt|t}}, an lvalue of type {{c|const std::remove_reference_t<T>}} and | * {{tt|t}}, an lvalue of type {{c|const std::remove_reference_t<T>}} and | ||
* {{tt|u}}, an lvalue of type {{c|const std::remove_reference_t<U>}}, | * {{tt|u}}, an lvalue of type {{c|const std::remove_reference_t<U>}}, | ||
the following are true: | the following are true: | ||
− | * {{c|t | + | * {{c|1=t == u}}, {{c|1=u == t}}, {{c|1=t != u}}, {{c|1=u != t}} have the same domain; |
* {{c|1=bool(u == t) == bool(t == u)}}; | * {{c|1=bool(u == t) == bool(t == u)}}; | ||
* {{c|1=bool(t != u) == !bool(t == u)}}; and | * {{c|1=bool(t != u) == !bool(t == u)}}; and | ||
* {{c|1=bool(u != t) == bool(t != u)}}. | * {{c|1=bool(u != t) == bool(t != u)}}. | ||
− | @ | + | @4@ {{c|__WeaklyEqualityComparableWith<T, U>}} is modeled only if: |
− | + | {{rrev multi|rev1=The corresponding {{lconcept|common_reference_with}} concept is modeled. | |
− | + | |since2=c++23|rev2= | |
+ | Let | ||
+ | * {{tt|C}} be {{c|std::common_reference_t<const T&, const U&>}}, | ||
+ | * {{tt|t1}} and {{tt|t2}} be [[cpp/concepts#Equality preservation|equality-preserving]] expressions that are lvalues of type {{c|std::remove_cvref_t<T>}}, | ||
+ | * {{tt|u1}} and {{tt|u2}} be [[cpp/concepts#Equality preservation|equality-preserving]] expressions that are lvalues of type {{c|std::remove_cvref_t<U>}}, | ||
+ | the following conditions hold: | ||
+ | * {{c|CONVERT_TO<C>(t1)}} equals {{c|CONVERT_TO<C>(t2)}} if and only if {{tt|t1}} equals {{tt|t2}}; and | ||
+ | * {{c|CONVERT_TO<C>(u1)}} equals {{c|CONVERT_TO<C>(u2)}} if and only if {{tt|u1}} equals {{tt|u2}}. | ||
+ | }} | ||
{{cpp/concepts/equality preservation}} | {{cpp/concepts/equality preservation}} | ||
{{cpp/concepts/implicit expression variations}} | {{cpp/concepts/implicit expression variations}} | ||
− | {{langlinks|ja|zh}} | + | ===References=== |
+ | {{ref std c++23}} | ||
+ | {{ref std|section=18.5.4|title=Concept {{tt|equality_comparable}}|id=concept.equalitycomparable}} | ||
+ | {{ref std end}} | ||
+ | {{ref std c++20}} | ||
+ | {{ref std|section=18.5.3|title=Concept {{tt|equality_comparable}}|id=concept.equalitycomparable}} | ||
+ | {{ref std end}} | ||
+ | |||
+ | {{langlinks|de|es|ja|ru|zh}} |
Latest revision as of 10:40, 7 September 2024
Defined in header <concepts>
|
||
template< class T > concept equality_comparable = __WeaklyEqualityComparableWith<T, T>; |
(1) | (since C++20) |
template< class T, class U > concept equality_comparable_with = |
(2) | (since C++20) |
Helper concepts |
||
template< class T, class U > concept __WeaklyEqualityComparableWith = |
(3) | (exposition only*) |
(4) | ||
template< class T, class U > concept __ComparisonCommonTypeWith = |
(until C++23) (exposition only*) |
|
template< class T, class U, class C = std::common_reference_t<const T&, const U&> > concept _ComparisonCommonTypeWithImpl = |
(since C++23) (exposition only*) |
|
std::equality_comparable
specifies that the comparison operators ==
and !=
on T
reflects equality: ==
yields true if and only if the operands are equal.std::equality_comparable_with
specifies that the comparison operators ==
and !=
on (possibly mixed) T
and U
operands yield results consistent with equality. Comparing mixed operands yields results equivalent to comparing the operands converted to their common type.__WeaklyEqualityComparableWith
specifies that an object of type T
and an object of type U
can be compared for equality with each other (in either order) using both ==
and !=
, and the results of the comparisons are consistent. __ComparisonCommonTypeWith
specifies that two types share a common type, and a const lvalue or a non-const rvalue(since C++23) of either type is convertible to that common type.Contents |
[edit] Semantic requirements
These concepts are modeled only if they are satisfied and all concepts they subsume are modeled.
In the following paragraphs, given an expression E
and a type C
, CONVERT_TO<C>(E) is defined as:
|
(until C++23) |
|
(since C++23) |
a
and b
of type T
, bool(a == b) is true if and only if a
and b
are equal. Together with the requirement that a == b is equality-preserving, this implies that ==
is symmetric and transitive, and further that ==
is reflexive for all objects a
that are equal to at least one other object.-
t
andt2
be lvalues denoting distinct equal objects of types const std::remove_reference_t<T> and std::remove_cvref_t<T> respectively, -
u
andu2
be lvalues denoting distinct equal objects of types const std::remove_reference_t<U> and std::remove_cvref_t<U> respectively, -
C
be std::common_reference_t<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>,
the following expression is true:
- bool(t == u) == bool(CONVERT_TO<C>(t2) == CONVERT_TO<C>(u2)).
-
t
, an lvalue of type const std::remove_reference_t<T> and -
u
, an lvalue of type const std::remove_reference_t<U>,
the following are true:
- t == u, u == t, t != u, u != t have the same domain;
- bool(u == t) == bool(t == u);
- bool(t != u) == !bool(t == u); and
- bool(u != t) == bool(t != u).
The corresponding |
(until C++23) |
Let
the following conditions hold:
|
(since C++23) |
[edit] Equality preservation
Expressions declared in requires expressions of the standard library concepts are required to be equality-preserving (except where stated otherwise).
[edit] Implicit expression variations
A requires expression that uses an expression that is non-modifying for some constant lvalue operand also requires implicit expression variations.
[edit] References
- C++23 standard (ISO/IEC 14882:2024):
- 18.5.4 Concept
equality_comparable
[concept.equalitycomparable]
- 18.5.4 Concept
- C++20 standard (ISO/IEC 14882:2020):
- 18.5.3 Concept
equality_comparable
[concept.equalitycomparable]
- 18.5.3 Concept