为什么 C++ Map 说该结构存在而实际上不存在?

zrl*_*rli 1 c++ stdmap

我有一个名为 foo 的结构体,还有一个名为 mp 的映射,但由于某种原因,当我插入 {5, 0, 3} 并查询 {5, 3, 0} 时,映射显示它包含 {5, 3 , 0} 当它实际上没有时:

#include <bits/stdc++.h>

using namespace std;

struct foo {
    int v1, v2, v3;
    friend bool operator<(const foo &a, const foo &b) {
        return a.v1 < b.v1;
    }
    friend bool operator==(const foo &a, const foo &b) {
        return (a.v1 == b.v1) && (a.v2 == b.v2) && (a.v3 == b.v3);
    }
};

int main() {    
    map<foo, int> mp;
    mp[{5, 0, 3}] = 1;
    if(mp[{5, 3, 0}]) {
        cout << "YES\n";
    } else {
        cout << "NO\n";
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

YES
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么我的代码这样做?如果是这样,我需要改变什么?

JaM*_*MiT 6

您的比较运算符与等于运算符不匹配。Astd::map不使用相等运算符;它使用“小于”。如果两者a < b都不是,b < a则地图认为ab是等价的。在你的情况下:

  • foo{5, 0, 3} < foo{5, 3, 0}false因为5 < 5是假的。
  • foo{5, 3, 0} < foo{5, 0, 3}false因为5 < 5是假的。

因此地图认为这些对象是等效的。因此mp[{5, 3, 0}]找到您刚刚设置为 1 的映射元素,因此它是一个真值。

为了获得您想要的结果,您operator<需要考虑所有三个成员,而不仅仅是v1

例如:

    friend bool operator<(const foo &a, const foo &b) {
        if (a.v1 != b.v1)
            return a.v1 < b.v1;
        if (a.v2 != b.v2)
            return a.v2 < b.v2;
        return a.v3 < b.v3;
    }
Run Code Online (Sandbox Code Playgroud)

或者(正如 PaulMcKenzie 建议的那样)更简单:

    friend bool operator<(const foo &a, const foo &b) {
        return std::tie(a.v1, a.v2, a.v3) < std::tie (b.v1, b.v2, b.v3);
    }
Run Code Online (Sandbox Code Playgroud)