简体   繁体   中英

operator< overload for std::set::insert not working as expected

I am trying to implement a std::set::insert such that it will 'insert' a struct given that one does not already exist.

I have added the required custom operator overload for 'less than' ( < ); however, when the code is executed it just seems to skip past it and not work as expected. (Implementation for which was modified (addition of the const noexcept was taken from here: C2676: binary '<': 'const _Ty' does not define this operator or a conversion to a type acceptable to the predefined operator )

Sample Code:

#include <set>

struct Coordinate
{
int x;
int y;

Coordinate(int x = 0, int y = 0) : x(x), y(y)
{
}

bool operator==(const Coordinate& obj)
{
    return x == obj.x && y == obj.y;
}

bool operator!=(const Coordinate& obj)
{
    return x != obj.x && y != obj.y;
}

bool operator< (const Coordinate& obj) const noexcept
{
    return x < obj.x && y < obj.y;
}
};

int main(){
std::set<Coordinate> current_set = {Coordinate(1, 2)};

Coordinate new_coordinate(1, 3);

current_set.insert(new_coordinate);
}

To be clear, with this implementation, the set does not get updated with the new_coordinate object even though the members clearly differ.

Any assistance on this would be appreciate.

Your implementation of operator< is incorrect for the purpose of std::set . It does not meet the requirements of strictly weak ordering .

Change it to:

bool operator<(const Coordinate& obj) const noexcept
{
    if ( x != obj.x )
    {
       return x < obj.x;
    }
    return y < obj.y;
}

You can simplify that by using std::tie .

bool operator<(const Coordinate& obj) const noexcept
{
    return std::tie(x, y) < std::tie(obj.x, obj.y);
}

std::set - cppreference.com says:

In imprecise terms, two objects a and b are considered equivalent if neither compares less than the other: ,comp(a, b) &&.comp(b, a).

The member x of the two objects Coordinate(1, 2) and Coordinate(1, 3) are both 1, so operator< cannot be true and therefore they are considered as same.

Commonly-used implementation will be like this:

  • A < B is true if Ax < Bx
  • A < B is false (because B < A is true) if AX > Bx
  • When Ax == Bx , A < B iff Ay < By
bool operator< (const Coordinate& obj) const noexcept
{
    return x < obj.x || (x == obj.x && y < obj.y);
}

To complement the other answers that explain the problem: Here is C++20 version of the class:

struct Coordinate
{
    int x;
    int y;
    
    friend auto
    operator<=>(const Coordinate&, const Coordinate&) = default;
};

int main()
{
    std::set<Coordinate> current_set = {{1, 2}};
    current_set.emplace(1, 3);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM