简体   繁体   English

运算符 < std::set::insert 的重载未按预期工作

[英]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.我正在尝试实现一个std::set::insert ,这样它将“插入”一个结构,因为该结构尚不存在。

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 ) (修改的实现(添加的const noexcept取自此处: C2676: binary '<': 'const _Ty' 未定义此运算符或转换为预定义运算符可接受的类型

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.需要明确的是,通过此实现,即使成员明显不同,该集合也不会使用new_coordinate object 进行更新。

Any assistance on this would be appreciate.对此的任何帮助将不胜感激。

Your implementation of operator< is incorrect for the purpose of std::set .std::set而言,您对operator<的实现不正确。 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 .您可以使用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: std::set - cppreference.com说:

In imprecise terms, two objects a and b are considered equivalent if neither compares less than the other: ,comp(a, b) &&.comp(b, a).用不精确的术语来说,如果两个对象 a 和 b 的比较都不小于另一个,则认为两个对象是等价的:,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.两个对象Coordinate(1, 2)Coordinate(1, 3)的成员x都是 1,因此operator<不能为真,因此它们被认为是相同的。

Commonly-used implementation will be like this:常用的实现会是这样的:

  • A < B is true if Ax < Bx如果Ax < Bx ,则A < B为真
  • A < B is false (because B < A is true) if AX > Bx如果AX > BxA < B为假(因为B < A为真)
  • When Ax == Bx , A < B iff Ay < ByAx == Bx , A < B当且仅当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:为了补充解释问题的其他答案:这是 class 的 C++20 版本:

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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