为何std::find未调用我重载的std::pair<int,int>的operator==?
问题:重载std::pair的operator==后std::find未调用自定义逻辑
尝试重载std::pair<int,int>的operator==,使其仅比较pair的第一个元素,期望std::find在std::vector<std::pair<int,int>>中查找时调用该重载,但实际仅直接比较语句有效,std::find未使用自定义逻辑。
预期输出:
1 1 1
实际输出:
1 1 0
运行环境:Linux、gcc 11.3
代码如下:
#include <iostream> #include <algorithm> #include <vector> #include <utility> using namespace std; typedef pair<int, int> p_int_t; bool operator==(const p_int_t& p1, const p_int_t& p2) { return p1.first == p2.first; } int main() { vector<p_int_t> v; v.push_back({1, 2}); v.push_back({1, 3}); p_int_t p(1, 4); cout << (v[0] == p) << endl; cout << (v[1] == p) << endl; cout << (find(v.begin(), v.end(), p) != v.end()) << endl; return 0; }
原因分析
- 直接比较的逻辑:代码中使用了
using namespace std;,全局命名空间的自定义operator==和std命名空间的默认operator==都在作用域内。由于自定义的operator==是非模板函数,而标准库的std::operator==是模板函数,重载决议时非模板函数优先级更高,所以直接比较时会调用自定义逻辑。 - std::find的逻辑:
std::find是std命名空间中的函数,在其内部执行比较操作时,会优先通过依赖于参数的查找(ADL)搜索参数类型所在的std命名空间,找不到全局命名空间的自定义重载,因此使用了标准库默认的operator==——该逻辑要求pair的两个元素都相等才返回true。示例中p的第二个元素是4,与vector中元素的第二个元素不匹配,所以std::find找不到匹配项,输出0。
解决方案
方案1:使用std::find_if+自定义谓词(推荐)
避免重载标准库类型的operator==,改用std::find_if并传入自定义lambda作为匹配条件,这是更安全、符合标准的做法:
修改后的代码:
#include <iostream> #include <algorithm> #include <vector> #include <utility> using namespace std; typedef pair<int, int> p_int_t; int main() { vector<p_int_t> v; v.push_back({1, 2}); v.push_back({1, 3}); p_int_t p(1, 4); cout << (v[0].first == p.first) << endl; cout << (v[1].first == p.first) << endl; auto it = find_if(v.begin(), v.end(), [&p](const p_int_t& elem) { return elem.first == p.first; }); cout << (it != v.end()) << endl; return 0; }
方案2:将重载放入std命名空间(不推荐)
虽然C++标准禁止用户向std命名空间添加自定义内容,但部分编译器(如gcc)会允许这种操作。将自定义的operator==放入std命名空间后,ADL就能找到它:
修改后的代码片段:
namespace std { bool operator==(const pair<int, int>& p1, const pair<int, int>& p2) { return p1.first == p2.first; } } // namespace std
注意:此方法属于未定义行为,可能在不同编译器或版本中出现问题,不建议在生产代码中使用。
内容的提问来源于stack exchange,提问作者sarzynek
相关产品推荐
相关产品推荐

