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.

Reply via email to