Why is equality needed for rel_ops? Isn't "<" enough?
a==b => !(a<b) && !(b<a)
It might be a very stupid question. Am I missing something?
Why is equality needed for rel_ops? Isn't "<" enough?
a==b => !(a<b) && !(b<a)
It might be a very stupid question. Am I missing something?
Why is equality needed for rel_ops? Isn't "<" enough?
a==b => !(a<b) && !(b<a)
Because this is not true in general. If rel_ops
would work only for relational operators that follow that logic it would be rather limited.
I guess what you have in mind is the weak ordering required for the <
operator for associative containers. From cppreference:
Everywhere the standard library uses the Compare requirements, uniqueness is determined by using the equivalence relation. In imprecise terms, two objects a and b are considered equivalent (not unique) if neither compares less than the other: !comp(a, b) && !comp(b, a).
In simple terms: Whether two keys are considered the "same" is only determined by requiring ! (a < b) && ! (b < a)
. Hence you only need to supply a <
for associative containers and no operator==
to decide whether two keys are the same. However, equivalence (!(a<b)&&!(b<a)
) is not necessarily the same as equality (a==b
).
For example when you use this
struct my_key {
int a;
int b;
bool operator< (const key_type& other) {
return a < other.a; // not comparing b !
}
};
as a key of a std::map
then my_key{1,0}
and my_key{1,2}
are equivalent ("same key"), even though they are not equal. As another example, consider a Point
in spherical coordinates where we choose to have a < b
when a
is closer to the origin than b
:
struct Point {
double radius;
double angle;
bool operator<(const Point& other) {
return radius < other.radius;
}
bool operator==(const Point& other) {
return (radius == other.radius) && (angle == other.angle);
}
}
Also here all three a < b
,b < a
and a == b
can be false at the same time.
Also note that (from cppreference)
As of C++20, std::rel_ops are deprecated in favor of operator<=>.
For the starship operator <=>
you can choose between
std::strong_ordering
std::weak_ordering
std::partial_ordering
std::strong_equality
std::weak_equality
Weak ordering is what is required eg for std::map
(eg my_key
or Point
), while for strong ordering equivalence and equality are basically the same. For more details and examples I refer you to this.
Yes, actually you are missing sth. And it is very fundamental. It is not about C++ or programing. It's about math. According to math, your statement is true if and only if "<" defines a strict weak ordering on its operand domain. Not every user-defined type with "less" rel_op has a weak ordering.