C++中重载的operator<无法作用于sort函数问题咨询
为什么你的std::pair重载operator<在sort里不生效?
这个问题确实挺让人困惑的,我来帮你拆解清楚原因,再给你几个靠谱的解决方案。
问题根源:std::sort默认用的是std命名空间内的比较逻辑
你在全局命名空间重载了std::pair<int,int>的operator<,但这里有两个关键细节导致sort没用到你的重载:
- 当你直接写
a < b时,编译器会通过**依赖于参数的查找(ADL)**同时检查全局命名空间和std命名空间(因为pair定义在std里)。你的重载是针对具体pii类型的非模板函数,比std里的模板版operator<更匹配,所以直接比较会调用你的逻辑,这就是为什么b<a的输出是对的。 - 但
std::sort默认使用的是std::less<pii>,而std::less的实现是在std命名空间里的。当它调用operator<时,会优先在std命名空间内查找,自然就用了std自带的pair比较规则——默认先比first元素,first相等才比second,所以你的vector排序后还是按first排序,输出了1 4和2 3。
解决方案
方案1:给sort传自定义比较函数
直接写一个比较函数,作为sort的第三个参数,强制让它使用你的排序逻辑:
#include <iostream> #include <vector> #include <algorithm> using namespace std; typedef pair<int,int> pii; // 自定义比较逻辑 bool comparePairs(const pii &a, const pii &b){ return a.second < b.second; } int main() { pii a,b; a=make_pair(1,4); b=make_pair(2,3); if(a<b) cout<<"a<b\n"; else cout<<"b<a\n"; vector<pii> v; v.push_back(a); v.push_back(b); // 传入自定义比较函数 sort(v.begin(),v.end(), comparePairs); for(auto x:v) cerr<<x.first<<" "<<x.second<<endl; return 0; }
方案2:用Lambda表达式(更简洁)
不需要单独写函数,直接在sort里用lambda表达式,代码更紧凑:
// 替换sort那一行即可 sort(v.begin(),v.end(), [](const pii &a, const pii &b){ return a.second < b.second; });
方案3:包装成自定义结构体(如果想重载operator<)
如果你还是希望通过重载operator<让sort自动识别,最好不要直接修改std::pair的行为(这属于标准未定义行为,容易出问题),而是把pair包装成自己的结构体:
#include <iostream> #include <vector> #include <algorithm> using namespace std; struct MyPair { int first; int second; // 重载operator<,按second排序 bool operator<(const MyPair &other) const { return this->second < other.second; } }; int main() { MyPair a = {1,4}, b = {2,3}; if(a<b) cout<<"a<b\n"; else cout<<"b<a\n"; vector<MyPair> v; v.push_back(a); v.push_back(b); sort(v.begin(),v.end()); // 现在会自动调用我们重载的operator< for(auto x:v) cerr<<x.first<<" "<<x.second<<endl; return 0; }
注意:别随便重载std容器的operator<
C++标准明确规定,除非是官方允许的模板特化,否则在std命名空间内添加或修改函数属于未定义行为。全局重载std::pair的operator<不仅会遇到像这次sort不生效的问题,还可能和其他依赖std默认逻辑的代码冲突,所以尽量避免这种写法。
内容的提问来源于stack exchange,提问作者Hieu Doan
相关产品推荐
相关产品推荐

