成员函数指针作为std::map的key遍历时报非法操作数错误如何解决
问题根本原因
std::map 是有序关联容器,要求key类型必须支持严格弱序比较,而C++标准没有为成员函数指针定义默认的 </> 比较运算符,所以编译器在实例化std::map<FuncPtr, float>时,找不到合法的比较运算符实现,才会抛出对应报错。
你其他位置相似逻辑没有问题,大概率是其他场景下map的key是支持默认比较的普通函数指针,或是你已经提前自定义了比较规则。
解决方案
有两种常用的解决思路:
方案1:改用不需要有序的std::unordered_map,自定义成员函数指针的哈希和相等判断逻辑
#include <unordered_map> #include <functional> using FuncPtr = void (Game::*)(UINT); // 自定义FuncPtr哈希规则 struct FuncPtrHash { size_t operator()(FuncPtr ptr) const { // C++20及以上推荐用std::bit_cast替代reinterpret_cast,安全性更高 return std::hash<uintptr_t>()(reinterpret_cast<uintptr_t&>(ptr)); } }; // 自定义FuncPtr相等判断 struct FuncPtrEqual { bool operator()(FuncPtr a, FuncPtr b) const { return a == b; } }; // 替换原有map定义 std::unordered_map<FuncPtr, float, FuncPtrHash, FuncPtrEqual> funcDelayedTriggerMap;
方案2:保留std::map,手动为成员函数指针自定义比较规则
using FuncPtr = void (Game::*)(UINT); // 自定义比较规则,先转为整数类型再做大小比较 struct FuncPtrCompare { bool operator()(FuncPtr a, FuncPtr b) const { return reinterpret_cast<uintptr_t&>(a) < reinterpret_cast<uintptr_t&>(b); } }; // 替换原有map定义 std::map<FuncPtr, float, FuncPtrCompare> funcDelayedTriggerMap;
额外逻辑修复
你当前遍历代码里的erase写法存在隐患:直接调用erase(it->first)后,原迭代器it会直接失效,后续执行++it会触发未定义行为,建议修改为安全的遍历删除写法:
void Game::PollProcessDelayedTriggers() { // 把时间获取移到循环外,避免每次循环重复调用 float currentS = m_timer.GetElapsedSeconds(); for (auto it = funcDelayedTriggerMap.begin(); it != funcDelayedTriggerMap.end(); ) { if (it->second < currentS) { (this->*(it->first))(UINT_MAX); // erase会返回下一个有效迭代器,不需要手动自增 it = funcDelayedTriggerMap.erase(it); } else { // 未删除元素时手动自增迭代器 ++it; } } }
内容的提问来源于stack exchange,提问作者Rikkles
相关产品推荐
相关产品推荐

