c++c++20stdvectorcomparison-operators

C++20 std::vector comparison weird behaviour


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?


Solution

  • C++20 replaces the individual <,<=,>,>= operators of std::vector (and of many other standard classes) with a single <=>.

    Internally it tries to use <=> to compare the elements, and falls back to the old operators if the type doesn't overload <=>.

    Since you have a non-explicit operator bool, applying <=> converts both operands to bool and compares those. The fix is to make operator bool explicit (which is a good idea in general) (so that <=> fails and vector falls back to the old operators), and/or replace <,<=,>,>= with <=> (which is also a good idea in general).