将std::function作为std::map键插入编译失败,求解决思路
解决std::function作为std::map键的编译问题
std::map默认使用std::less作为比较器,要求键类型必须支持严格弱序的operator<比较,但std::function并没有默认实现这个运算符,这就是代码编译失败的核心原因。下面是几种可行的解决思路:
1. 给std::map指定自定义比较器
自定义一个比较规则,针对std::function绑定的目标进行比较(仅对函数指针、成员函数指针这类有固定地址的可调用对象有效):
#include <functional> #include <map> #include <string> int sum(int a, float b){ return a+b; } struct FuncCompare { template<typename Func> bool operator()(const Func& lhs, const Func& rhs) const { // 先判断类型是否一致,再比较目标函数的地址 if (lhs.target_type() != rhs.target_type()) { return lhs.target_type().name() < rhs.target_type().name(); } auto lhs_ptr = lhs.target<int(*)(int, float)>(); auto rhs_ptr = rhs.target<int(*)(int, float)>(); return lhs_ptr && rhs_ptr && *lhs_ptr < *rhs_ptr; } }; int main() { std::function<int(int, float)>f = sum; std::map<std::function<int(int, float)>, std::string, FuncCompare> mapa; mapa.insert(std::make_pair(f, "sum")); }
注意:如果std::function绑定的是lambda、std::bind生成的对象这类无固定地址的可调用体,target()会返回nullptr,这种方法就会失效。
2. 改用std::unordered_map并自定义哈希与相等判断
如果不需要有序映射,换成哈希表std::unordered_map,同时提供自定义的哈希函数和相等判断逻辑:
#include <functional> #include <unordered_map> #include <string> #include <typeindex> int sum(int a, float b){ return a+b; } struct FuncHash { template<typename Func> size_t operator()(const Func& func) const { // 结合类型信息和目标地址生成哈希值 size_t hash = std::hash<std::type_index>()(std::type_index(func.target_type())); if (auto ptr = func.target<int(*)(int, float)>()) { hash ^= std::hash<decltype(ptr)>()(ptr) << 1; } return hash; } }; struct FuncEqual { template<typename Func> bool operator()(const Func& lhs, const Func& rhs) const { if (lhs.target_type() != rhs.target_type()) return false; auto lhs_ptr = lhs.target<int(*)(int, float)>(); auto rhs_ptr = rhs.target<int(*)(int, float)>(); return lhs_ptr && rhs_ptr && *lhs_ptr == *rhs_ptr; } }; int main() { std::function<int(int, float)>f = sum; std::unordered_map<std::function<int(int, float)>, std::string, FuncHash, FuncEqual> mapa; mapa.insert(std::make_pair(f, "sum")); }
局限性:匿名lambda这类可调用对象无法通过此方法判断相等,因为每个lambda的类型都是唯一的,即使代码逻辑完全相同。
3. 替换键类型(推荐)
最可靠的方式是避免直接用std::function当键,改用更适合作为键的类型,比如:
- 直接用函数指针作为键(仅适用于普通函数/静态成员函数)
- 用自定义的唯一标识(如枚举、字符串ID)作为键,将
std::function存在map的值中
示例代码:
#include <functional> #include <map> #include <string> int sum(int a, float b){ return a+b; } int main() { // 方案1:用函数指针做键 std::map<int(*)(int, float), std::string> func_map; func_map.insert(std::make_pair(sum, "sum")); // 方案2:用字符串ID映射function(更灵活) std::map<std::string, std::function<int(int, float)>> id_map; id_map["sum"] = sum; }
这种方法完全避开了std::function作为键的比较问题,适用性最广。
内容的提问来源于stack exchange,提问作者black_gay
相关产品推荐
相关产品推荐

