C++:为何无法在同一结构体中重载priority_queue用的operator()?
问题场景
我尝试在同一个结构体中重载用于priority_queue的比较逻辑的operator()时出现语法错误,但将比较逻辑定义在单独结构体中却能正常运行,示例代码如下:
struct myC { int i; myC(int x){ this -> i = x; } // 语法错误 // bool operator()(myC &a, myC &b) { // return a.i < b.i; // } bool operator()(myC &b) { return this ->i < b.i; } }; int main() { // your code goes here priority_queue<myC, vector<myC>, myC> q; q.push(myC(10)); q.pop(); return 0; }
编辑补充:operator()并非比较器运算符,而是函数调用运算符。
问题原因
成员函数的隐含this指针:结构体中的非静态
operator()是成员函数,会默认携带一个this指针作为第一个隐式参数。你尝试定义的双参数operator(),实际签名是bool operator()(myC* this, myC& a, myC& b),这和priority_queue要求的比较器签名bool(myC&, myC&)完全不匹配,因此触发语法错误。单参数operator()的误区:你写的单参数
operator()是一元函数调用运算符,它只能用当前结构体实例和另一个实例做比较,但priority_queue需要的是一个能独立比较任意两个实例的可调用体。另外,当你把myC作为比较器类型传入时,priority_queue会尝试默认构造一个比较器实例,但你的myC没有默认构造函数,这也会导致后续编译错误。单独结构体的合理性:单独的比较器结构体中,
operator()是普通成员函数,没有隐含的this指针,签名完全符合priority_queue的要求——接收两个同类型参数并返回bool,因此可以正常工作。
解决方案
方案一:使用独立的比较器结构体(常规做法)
这是C++中实现priority_queue比较器最常用的方式,逻辑清晰,耦合度低:
struct myC { int i; myC(int x) : i(x) {} // 用初始化列表初始化成员,比赋值更规范 }; // 独立的比较器结构体 struct myCComparator { // 使用const引用避免不必要的拷贝,同时保证能处理const对象 bool operator()(const myC& a, const myC& b) { return a.i < b.i; // 此逻辑对应大顶堆(默认),若要小顶堆改为a.i > b.i } }; int main() { priority_queue<myC, vector<myC>, myCComparator> q; q.push(myC(10)); q.pop(); return 0; }
方案二:将比较器operator()设为静态成员函数
如果一定要把比较逻辑和元素类型放在同一个结构体中,可以把operator()定义为静态成员——静态成员函数没有隐含的this指针,签名符合priority_queue的要求:
struct myC { int i; myC(int x) : i(x) {} static bool operator()(const myC& a, const myC& b) { return a.i < b.i; } }; int main() { priority_queue<myC, vector<myC>, myC> q; q.push(myC(10)); q.pop(); return 0; }
注:静态成员函数不依赖结构体实例,因此即使myC没有默认构造函数,priority_queue也能正常使用这个比较器。
内容的提问来源于stack exchange,提问作者ProgramCpp

