grater<int>
的实现可以简化为:
template<typename T>
struct greater {
constexpr bool operator()(const T &left, const T &right) const {
return left > right;
}
};
换句话说,任何 greater
的对象都有一个运算符(),它能让对象以类似函数的语法执行一个功能,也就是仿函数。
greater<int> a; // 创建实例
bool result = a(1, 2); // 调用重载的 () 方法
T v
这种语法是声明的同时创建,如果你需要创建一个匿名的临时对象,就用 T()
,例如 greater<int>()
。
sort(A, B, C)
是函数调用,你得传递一个值或对象,类型标识符不是值,你得调用构造函数返回一个对象,greater<int>()
就是创建了一个类型为 greater<int>
的对象。
priority_queue<int, vector<int>, greater<int>>
尖括号里的是模板参数,它填写的是类型标识符,因为类型只给编译器看,运行时是没有类型的,所以不应该创建一个对象,只需要告诉编译器我用哪个类型即可。
假设 priority_queue
的第三个类型参数叫 Comp
,那么内部会有类似这样的代码:
template<typename T, typename Container, typename Comp>
class priority_queue {
...
Comp cmp;
...
void push(const T &value) {
...
// 如果 value 应当排在 other 前面
if (cmp(value, other)) {
...
}
...
}
};
使用 Comp
主要是为了自定义偏序,否则你将只能对定义了小于运算符的对象做排序。可以看到,实现中只需要 cmp(a, b)
这样的语法,因此你的第一反应是 cmp
应当是一个函数,Comp
的类型应当是函数指针,比如
priority_queue<int, vector<int>, bool (*)(const int&, const int&)> q;
但这样会导致 cmp
变量没有初始值,从而为 NULL
,你还得单独传递一个函数给构造方法。什么情况能让成员字段在声明的同时就有默认值?当然是对象!又考虑到绝大多数情况我们仍然使用对象的大于小于关系, 我们可以把比较的预设函数定义在对象中。但这样一来我们就得用类似 cmp.fn(a, b)
的方式比较,能不能不改变之前的语法?那就允许重载 ()
就行了,把这个 fn
用 operator()
代替。