std::sort
为啥不需要 decltype
,而 priority_queue
有时却需要?
我们来彻底讲清楚它们底层的原理和差别,并帮你记住什么时候用 decltype
。
✅ 先说现象:你写的两种用法
✅ std::sort
示例:
bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
return a.first < b.first;
}
sort(v.begin(), v.end(), cmp); // 没有用 decltype
✅ priority_queue
示例:
bool cmp(const pair<int, int>& a, const pair<int, int>& b) {
return a.first > b.first;
}
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp); // 用了 decltype
🧠 根本区别在于:函数 vs 模板参数
🟦 std::sort
的第三个参数是一个函数对象(Function Pointer 或 Lambda),是运行时传参
你传的是一个函数(或者函数指针):
sort(..., cmp); // cmp 是个函数,函数指针类型自动推导
它不需要你提前告诉它类型。
🟥 priority_queue
的比较器是模板参数,是编译期类型确定
template<
class T,
class Container = vector<T>,
class Compare = less<typename Container::value_type>
> class priority_queue;
这个 Compare
是类模板参数,你必须告诉编译器它是什么类型。如果你传的是一个函数指针 cmp
,它就需要 decltype(&cmp)
来知道这个函数的类型。
✅ 所以为什么要 decltype(&cmp)
?
因为 cmp
是函数名,本身代表函数地址(函数指针)。你不能直接写:
priority_queue<..., cmp> q(cmp); // ❌ 错误,cmp 不是一个类型
但你可以通过:
decltype(&cmp) // 获取 cmp 的函数指针类型:bool (*)(const pair<int,int>&, const pair<int,int>&)
从而告诉编译器你传的是一个函数指针类型。
✅ 那 sort 为啥不用 decltype
呢?
因为 sort()
是函数模板,它第三个参数本身是一个函数对象,直接传一个函数或 lambda 就行了,编译器能推导出类型,不需要你显式说明。
✅ 最推荐的做法是用 struct 比较器,而不是 function 指针
你其实可以完全避免 decltype
,写成这样:
struct Cmp {
bool operator()(const pair<int, int>& a, const pair<int, int>& b) const {
return a.first > b.first;
}
};
priority_queue<pair<int, int>, vector<pair<int, int>>, Cmp> q;
这样更安全、支持 inline 优化,不涉及函数指针、decltype,写法更简洁。
✅ 一句话总结:
sort
用的是函数参数,编译器能自动推导类型,不用写类型名;而priority_queue
的比较器是类模板参数,需要提前告诉编译器类型是什么,所以必须用decltype(&cmp)
或struct Cmp
显式声明。
–