C++实现不同自定义比较器的map构成vector时纯虚operator()报错的正确解法
报错根因
std::map的第三个模板参数为比较器的静态类型,要求该类型可实例化、支持值语义。- 直接将带有纯虚函数的抽象类
head<int>作为map的比较器类型传入时,map内部需要构造一个head<int>类型的比较器成员,抽象类无法实例化,因此直接触发编译错误。 std::map的类型系统为静态绑定,不支持在模板参数位置传入抽象基类来实现运行时多态的比较逻辑。
正确实现思路
要实现“同一vector中存储多个不同比较逻辑的map实例”,核心是对比较器做类型擦除,将所有不同类型的可调用比较器统一封装为一个可实例化的通用类型,也就是用标准库提供的std::function作为map的比较器类型:
std::function本身是可实例化的值语义类型,完全满足std::map对比较器类型的要求。std::function可以包装任意匹配签名(输入两个const int&,输出bool)的可调用对象,无论是自定义的继承类比较器、函数指针还是lambda表达式。- 所有采用
std::function作为比较器的map实例拥有统一的静态类型,可以正常存入同一个std::vector中。
可运行的修改后代码
#include<iostream> #include<map> #include<vector> #include<functional> #include<cstdlib> template <class T> struct head { virtual bool operator() (const T& x, const T& y) const = 0; }; template <class T> struct greater: head<T> { bool operator() (const T& x, const T& y) const {return x>y;} }; template <class T> struct less: head<T> { bool operator() (const T& x, const T& y) const {return x<y;} }; int main() { // 定义统一的map类型:比较器为可擦除的std::function类型 using DynamicIntMap = std::map<int, int, std::function<bool(const int&, const int&)>>; std::vector<DynamicIntMap> mp; // 为vector中每个map实例绑定独立的比较器 // 1. 第一个map:按数值升序排列 mp.emplace_back(DynamicIntMap(less<int>{})); // 2. 第二个map:按数值降序排列 mp.emplace_back(DynamicIntMap(greater<int>{})); // 3. 第三个map:自定义按绝对值升序排列,无需继承head基类 mp.emplace_back(DynamicIntMap([](const int& a, const int& b){ return std::abs(a) < std::abs(b); })); // 验证自定义比较器效果 auto& abs_sorted_map = mp[2]; abs_sorted_map[-5] = 1; abs_sorted_map[3] = 2; abs_sorted_map[-2] = 3; for (const auto& [key, val] : abs_sorted_map) { std::cout << key << " "; // 输出顺序为-2 3 -5,符合绝对值升序预期 } return 0; }
关键注意事项
- 不要使用
std::map<int, int, head<int>*>这类指针类型作为比较器:这种写法虽然能绕过抽象类实例化的编译错误,但需要手动管理比较器对象的生命周期,极易出现野指针、内存泄漏问题,安全性远低于值语义的std::function。 - 禁止默认构造空比较器的map实例:当
std::function没有绑定任何可调用对象时,对map执行插入、查找等操作会抛出std::bad_function_call异常,因此必须在创建map实例时就传入有效的比较器对象。 - 该方案完全复用已定义的比较器继承体系,不需要修改原有
head、greater、less结构体的实现。
内容的提问来源于stack exchange,提问作者The Philomath
相关产品推荐
相关产品推荐

