https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100330
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> --- Reduced: #include <utility> extern "C" int puts(const char*); struct vertex_descriptor { operator bool() const { puts(__func__); return i; } bool operator<(const vertex_descriptor b) const { puts(__func__); return i < b.i; } int i = 0; }; int main() { std::pair<vertex_descriptor, int> p1({1}, 0); std::pair<vertex_descriptor, int> p2({2}, 0); if (!(p1 < p2)) throw 1; } This aborts in C++20. I think GCC is correct according to the standard. In C++20 the operator< for std:pair<T,U> is synthesized from operator<=>. That uses the synth-three-way helper defined in http://wg21.link/expos.only.func which determines that vertex_descriptor is three-way-comparable, and so uses <=> to compare them. But that uses your implicit conversion to bool, i.e. it is equivalent to p1.first==true <=> p2.first==true An explicit operator bool avoids the problem, because synth-three-way will not implicitly convert the operands to bool, and so will do: if (p1.first < p2.first) return weak_ordering::less; if (p2.first < p1.first) return weak_ordering::greater; return weak_ordering::equivalent; This uses vertex_descrioptor::operator< as intended.