Overloading the operator bool()
for a custom class T
breaks std::vector<T>
comparison operators.
The following code tried on the first online compiler google suggest me prints
v1 > v2: 0
v1 < v2: 1
when operator bool()
is commented and
v1 > v2: 0
v1 < v2: 0
when it's uncommented.
#include <iostream>
#include <vector>
class T {
int _value;
public:
constexpr T(int value) : _value(value) {}
constexpr bool operator==(const T rhs) const { return _value == rhs._value; }
constexpr bool operator!=(const T rhs) const { return _value != rhs._value; }
constexpr bool operator <(const T rhs) const { return _value < rhs._value; }
constexpr bool operator >(const T rhs) const { return _value > rhs._value; }
//constexpr operator bool() const { return _value; } // <-- breaks comparison
};
int main()
{
auto v1 = std::vector<T>{1,2,3};
auto v2 = std::vector<T>{1,2,9};
std::cout << "v1 > v2: " << (v1 > v2) << std::endl;
std::cout << "v1 < v2: " << (v1 < v2) << std::endl;
return 0;
}
This appears to be true only starting from C++20. What's changed underneath in std::vector
?
<=>
over<
. – Terminusoperator<
, so what's the explanation-chain that makes it work or not work, depending on whetheroperator bool
is there or not? – Wautersconstexpr auto operator<=>(const T& rhs) const = default;
. No need to define each operator by hand. – Severance<=>
being the better C++20 solution, andfriend auto operator<=>(const T&, const T&) = default;
would be enough to have the compiler implement it for you in this case). – Carola<=>
uses an implicit bool conversion, or why the C++ standard decided it's a good idea to prefer a synthesized<=>
over a provided<
-- but for now, I guess having read about this at some point should suffice. I rarely use conversion operators anyway, and never an implicit bool, so I still feel reasonably safe :-) – Wauters=default
onoperator==
andoperator!=
in C++20, and foroperator<=>
of course. – Forbisx <=> y
can mean here. There's no candidate forx.operator<=>(y)
. But there is one foroperator<=>(x, y)
- which isoperator<=>((bool)x, (bool)y)
. There's no way to differentiate in the language between "operator<=>
works because you provided it" and "operator<=>
works because you inherited it from an implicit conversion but you really had meant to useoperator<
". – Fie