问题实例
假设当前存在对象Widget,其具备重量与最高速度属性:1
2
3
4
5
6
7class Widget {
public:
...
size_t weight() const;
size_t maxSpeed() const;
...
};
我们默认以重量为排序方式,所以Widget::operator<
如下:1
2
3bool operator<(const Widget& lhs, const Widget& rhs){
return lhs.weight() < rhs.weight();
}
但如果我们想建立一个按照最高速度排序的multiset<Widget>
,而我们又知道默认的比较函数是less<Widget>
,而默认的less<Widget>
又调用operator<
工作。那似乎我们必须特化less<Widget>
来切断less<Widget>
与operator<
之间的纽带,让它只关心speed:1
2
3
4
5
6template<>//less针对Widget的一个特化
struct std::less<Widget>:public std::binary_function<Widget,Widget,bool> {
bool operator()(const Widget& lhs, const Widget& rhs) const{
return lhs.maxSpeed() < rhs.maxSpeed();
}
};
这种行为是在特化std namespace里面的模板,虽然std禁止了大部分修改操作,但这种自定义模板特化还是允许的。(Effective C++ 26 也执行了这样的操作)
但令less做除operator<以外的事情是对预期行为的无故破坏,就像你不应该把operator+重载成乘法一样。
解决方案
STL中没有一个用到less的地方你不能指定一个不同的比较类型。比如说我们可以建立一个名字不叫less的仿函数类:1
2
3
4
5
6struct MaxSpeedCompare:public binary_function<Widget, Widget, bool> {
bool operator()(const Widget& lhs, const Widget& rhs) const{
return lhs.maxSpeed() < rhs.maxSpeed();
}
};
multiset<Widget, MaxSpeedCompare> widgets;//自定义比较器
我们不应该切断less<T>
与operator<
的关联性,如果你确有需要,应当在声明容器时同时声明自定义比较器。