C++如何创建存储成员函数指针的类成员unordered_map
编译错误的核心原因
原代码的类型定义存在本质不匹配:非静态类成员函数的指针和普通全局函数指针是两种完全不兼容的类型。
原本定义的typedef void (*operation)();是指向无参数、无返回值的全局/静态函数的指针类型,但&Foo::operation1属于Foo类的非静态成员函数指针,必须绑定具体类实例才能调用,二者无法互相赋值,因此编译器找不到匹配的构造函数初始化unordered_map。
除此之外原代码还有两个隐藏问题:
- 调用逻辑错误:普通函数指针可以直接解引用调用,但非静态成员函数指针必须绑定类实例后才能触发调用
- 接口调用错误:const修饰的unordered_map不能使用非const的
operator[]取值(该接口会在key不存在时插入默认值,会修改容器内容),即使类型修正后也会触发编译错误
修正后的可编译实现
- 调整成员函数指针的类型定义,匹配Foo类的非静态成员函数签名
- 修正execute函数的调用逻辑,将映射表中取出的成员函数指针绑定到当前调用实例
this上 - const映射表取值时使用兼容const接口的
at()方法 - 补充类内静态成员的类外定义(C++语法要求:非字面常量类型的静态类成员,仅在类内声明不够,必须在全局作用域提供单独的实体定义,否则会触发链接阶段的未定义引用错误)
修正后的完整代码:
#include <unordered_map> #include <stdexcept> class Foo { public: void execute(char c) { // 绑定当前实例调用对应成员函数,使用at()匹配const map的接口要求 (this->*opcodes.at(c))(); } void operation1() { // 正常访问实例成员value_ } void operation2(); private: // 修正类型为Foo类的非静态成员函数指针 typedef void (Foo::*operation)(); // 类内仅声明静态映射 static const std::unordered_map<char, operation> opcodes; int value_; }; // 类外的静态成员定义 const std::unordered_map<char, Foo::operation> Foo::opcodes{ {'1', &Foo::operation1}, {'2', &Foo::operation2} }; // 补充operation2的定义 void Foo::operation2() { // 对应操作逻辑 } int main() { Foo foo; foo.execute('1'); return 0; }
关于该unordered_map能否定义为constexpr的说明
- 标准C++(截至C++23)并未实现constexpr版本的std::unordered_map。unordered_map基于动态哈希表实现,其内部的节点分配、哈希冲突处理逻辑未被标准纳入constexpr兼容范围,因此无论存储什么内容,都无法将unordered_map类型的静态成员声明为constexpr。
- 如果需要编译期初始化的常量表替代方案,可以换用constexpr兼容的容器,比如C++20起支持constexpr的
std::array、std::map,但这类容器的查找逻辑和unordered_map有差异,需要根据实际场景取舍。 - 实际工程中,将静态unordered_map声明为启动阶段完成初始化的const常量,已经可以获得足够的运行时性能,绝大多数场景和constexpr版本没有可感知的差异。
内容的提问来源于stack exchange,提问作者i spin and then i lock
相关产品推荐
相关产品推荐

