Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/concepts/equality comparable"

From cppreference.com
< cpp‎ | concepts
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 __WeaklyEqualityComparableWith = // exposition only
+
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 } -> std::boolean;
+
        { t == u } -> boolean-testable;
      { t != u } -> std::boolean;
+
        { t != u } -> boolean-testable;
      { u == t } -> std::boolean;
+
        { u == t } -> boolean-testable;
      { u != t } -> std::boolean;
+
        { u != t } -> boolean-testable;
 
     };
 
     };
 
}}
 
}}
{{dcl|since=c++20|num=2|1=
+
{{dcl rev begin|num=4}}
template < class T >
+
{{dcl|until=c++23|notes={{mark expos}}|1=
concept equality_comparable = __WeaklyEqualityComparableWith<T, T>;
+
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++20|num=3|1=
+
{{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 equality_comparable_with =
+
concept _ComparisonCommonTypeWithImpl =
  std::equality_comparable<T> &&
+
    std::same_as<std::common_reference_t<const T&, const U&>,
  std::equality_comparable<U> &&
+
                std::common_reference_t<const U&, const T&>> &&
  std::common_reference_with<
+
    requires {
    const std::remove_reference_t<T>&,
+
        requires std::convertible_to<const T&, const C&> {{!!}}
    const std::remove_reference_t<U>&> &&
+
            std::convertible_to<T, const C&>;
  std::equality_comparable<
+
        requires std::convertible_to<const U&, const C&> {{!!}}
     std::common_reference_t<
+
            std::convertible_to<U, const C&>;
      const std::remove_reference_t<T>&,
+
     };
      const std::remove_reference_t<U>&>> &&
+
template< class T, class U >
  __WeaklyEqualityComparableWith<T, U>;
+
concept __ComparisonCommonTypeWith =
 +
    _ComparisonCommonTypeWithImpl<std::remove_cvref_t<T>, std::remove_cvref_t<U>>;
 
}}
 
}}
 +
{{dcl rev end}}
 
{{dcl end}}
 
{{dcl end}}
  
@1@ The exposition-only concept {{tt|__WeaklyEqualityComparableWith<T, U>}} 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|{{==}}}} and {{tt|!{{=}}}}, and the results of the comparisons are consistent.  
+
@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|equality_comparable<T>}} 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|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|equality_comparable_with<T, U>}} 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 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 {{==}} u}}, {{c|u {{==}} t}}, {{c|t !{{=}} u}},{{c|u !{{=}} t}} have the same domain;
+
* {{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)}}.
  
@2@ {{tt|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 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.
+
@4@ {{c|__WeaklyEqualityComparableWith<T, U>}} is modeled only if:
 
+
{{rrev multi|rev1=The corresponding {{lconcept|common_reference_with}} concept is modeled.
@3@ {{tt|equality_comparable_with<T, U>}} is modeled only if, given any lvalue {{tt|t}} of type {{c|const std::remove_reference_t<T>}} and any lvalue {{tt|u}} of type {{c|const std::remove_reference_t<U>}}, and let {{tt|C}} be {{c|std::common_reference_t<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>}}, {{c|1=bool(t == u) == bool(C(t) == C(u))}}.
+
|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 =
    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>;
(2) (since C++20)
Helper concepts
template< class T, class U >

concept __WeaklyEqualityComparableWith =
    requires(const std::remove_reference_t<T>& t,
             const std::remove_reference_t<U>& u) {
        { t == u } -> boolean-testable;
        { t != u } -> boolean-testable;
        { u == t } -> boolean-testable;
        { u != t } -> boolean-testable;

    };
(3) (exposition only*)
(4)
template< class T, class U >

concept __ComparisonCommonTypeWith =
    std::common_reference_with<
        const std::remove_reference_t<T>&,

        const std::remove_reference_t<U>&>;
(until C++23)
(exposition only*)
template< class T, class U, class C = std::common_reference_t<const T&, const U&> >

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>>;
(since C++23)
(exposition only*)
1) The concept std::equality_comparable specifies that the comparison operators == and != on T reflects equality: == yields true if and only if the operands are equal.
2) The concept 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.
3) The exposition-only concept __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.
4) The exposition-only concept __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)
  • static_cast<const C&>(std::as_const(E)) if that is a valid expression,
  • static_cast<const C&>(std::move(E)) otherwise.
(since C++23)
1) std::equality_comparable<T> is modeled only if, given objects 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.
2) std::equality_comparable_with<T, U> is modeled only if, let

the following expression is true:

  • bool(t == u) == bool(CONVERT_TO<C>(t2) == CONVERT_TO<C>(u2)).
3) __WeaklyEqualityComparableWith<T, U> is modeled only if given

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).
4) __WeaklyEqualityComparableWith<T, U> is modeled only if:

The corresponding common_reference_with concept is modeled.

(until C++23)

Let

the following conditions hold:

  • CONVERT_TO<C>(t1) equals CONVERT_TO<C>(t2) if and only if t1 equals t2; and
  • CONVERT_TO<C>(u1) equals CONVERT_TO<C>(u2) if and only if u1 equals u2.
(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]
  • C++20 standard (ISO/IEC 14882:2020):
  • 18.5.3 Concept equality_comparable [concept.equalitycomparable]