c++重载运算符()change std::set.find()

cld4siwp  于 2023-01-28  发布在  其他
关注(0)|答案(1)|浏览(220)

我正在学习std::set。下面是我的代码:

#include <set>
#include <iostream>
using namespace std;
struct cmp{
    bool operator () (const int & a,const int & b) const {
        if(abs(a-b)<=3)
            return false;
        return a < b;
    }
};
set<int,cmp> q{1, 2, 10};
int main(){
    if(q.find(4)!=q.end())
        cout << 1;
    else
        cout << 2;
}

产量:1
我使用structcmp自定义元素的排序规则,如果abs(a-b)〈=3,新元素将被删除。
但是让我吃惊的是q.find()被修改了。
我想知道为什么输出是1,q中没有4。
find(4)是要得到一个迭代器,其中q中的元素等于4,对吗?

a9wyjsp7

a9wyjsp71#

您似乎希望set使用比较器来检查两个元素是否相等(编辑:在第二次读取时,实际上不是,您没有检查是否相等,但这对答案没有太大影响)。不是这样的。set不关心是否相等。当

!(cmp(a,b) && !(cmp(b,a)

考虑整数和cmp == std::less的简单情况,那么这就是

!(a < b) && !( b < a)

对于整数,当a == b时,只能是true。然而,一般来说,等价并不等于相等。在任何情况下,当两个元素可以被认为等价时,不应该是cmp返回true。当两个元素排序时,当ab之前时,cmp(a,b)应该是true
只有当cmp实现严格的弱排序时,这才能一致地工作,正如您在这里看到的:https://en.cppreference.com/w/cpp/named_req/Compare
您的代码具有未定义的行为,因为您的比较器不满足该要求。它没有实现严格的弱排序。
也没有明显的方法来解决这个问题,因为您比较两个元素的方法不能用来对它们进行排序。

// 1 and 3 are equivalent because 
!cmp(1,3) && !cmp(3,1) == !false && !false == true

// 3 and 5 are equivalent because 
!cmp(3,5) && !cmp(5,3) == !false && !false == true

但是

// 1 and 5 are not equivalent because 
!(cmp(1,5) && !cmp(5,1) == !true && !false == false

这是不一致的。草率地说,如果两个元素是等价的,那么在排序时如何排列它们并不重要。1和3如何相对于彼此排列并不重要,你可以在不破坏顺序的情况下交换它们。3和5也是如此。但是顺序对1和5很重要。这是不一致的。形式上,它打破了严格弱序的最后一个要求,正如塞巴斯蒂安Redl在评论中所指出的。

相关问题