You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

成员函数指针作为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 07:06:01