This stems from imprecise specification, which has since been rectified.
In C++17, these comparisons were specified as:
Requires: The expression *x == *y
shall be well-formed and its result shall be convertible to bool
.
Requires was a precondition, so failing to meet these conditions would be undefined behavior. But there are many different kinds of "preconditions" - does it mean check this statically, does this mean remove the operator from the overload set if the conditions aren't met, does it mean actual undefined behavior?
In C++20, these are instead specified as:
Mandates: The expression *x == *y
is well-formed and its result is convertible to bool
.
Which means that the program is ill-formed if the conditions aren't met. Basically, a mandate is a static_assert
(or equivalent).
So yes, the standard library is obligated to reject types whose comparison either doesn't exist or doesn't give you something like a bool
. This was never actually going to give you undefined behavior (what would an implementation do if it didn't have such an operator, read a bit from /dev/random
?) but now it's just much more clearly specified.
These changes came from a series of papers by Marshall Clow entitled "Mandating the Standard Library", this one specifically from P1460 (thanks, Marshall!). The new terminology for specifying the standard library comes from Walter Brown's "Guidelines for Formulating Library Semantics Specifications" paper (P1369).
T
having a strangeT::operator==
– Thamoperator==
at all? Not sure why it's UB rather than ill-formed... – Eos