如何为C++成员函数指针实现比较/小于运算符?
合规比较成员函数指针的方法
在C++中,普通指针可通过operator<或std::less进行比较,这让指针能作为std::map的键或有序列表元素。但成员函数指针的比较存在限制,比如以下代码会因找不到operator<而无法编译:
#include <map> class Base { public: //... }; class A : public Base { public: bool a(int v) { return v < 10; } }; class B : public Base { public: bool b(int v) { return v > 10; } }; using Fn = bool (Base::*)(int); int main() { A a; B b; Fn fn1 = static_cast<Fn>(&A::a); Fn fn2 = static_cast<Fn>(&B::b); std::map<Fn, Base*> functions; functions[fn1] = &a; functions[fn2] = &b; return 0; };
之前尝试用reinterpret_cast将成员函数指针转为void*实现比较,虽能编译但会产生警告,且属于不合规范的写法。需求源于实现C++状态机,需用map存储以成员方法实现的状态与历史记录的映射,因此需要合规的成员函数指针比较方案。
合规解决方案
方案1:自定义比较器,逐字节比较指针内存
利用std::memcmp比较成员函数指针的原始字节表示,这是完全合规的做法——仅对比内存字节,不依赖指针语义,能生成std::map所需的严格弱序。
#include <map> #include <cstring> class Base { public: //... }; class A : public Base { public: bool a(int v) { return v < 10; } }; class B : public Base { public: bool b(int v) { return v > 10; } }; using Fn = bool (Base::*)(int); // 自定义比较器 struct MemberFuncPtrLess { bool operator()(Fn lhs, Fn rhs) const { return std::memcmp(&lhs, &rhs, sizeof(Fn)) < 0; } }; int main() { A a; B b; Fn fn1 = static_cast<Fn>(&A::a); Fn fn2 = static_cast<Fn>(&B::b); // 使用自定义比较器初始化map std::map<Fn, Base*, MemberFuncPtrLess> functions; functions[fn1] = &a; functions[fn2] = &b; return 0; };
方案2:为成员函数指针分配唯一ID
通过辅助映射将每个成员函数指针关联到唯一整数ID,后续用ID进行比较。这种方法直观且完全符合标准,适合需要明确排序逻辑的场景。
#include <map> #include <atomic> class Base { public: //... }; class A : public Base { public: bool a(int v) { return v < 10; } }; class B : public Base { public: bool b(int v) { return v > 10; } }; using Fn = bool (Base::*)(int); // 辅助映射:成员函数指针 -> 唯一ID std::map<Fn, int> func_id_map; std::atomic<int> next_id = 0; // 获取指针对应的唯一ID int get_func_id(Fn fn) { if (!func_id_map.contains(fn)) { func_id_map[fn] = next_id++; } return func_id_map[fn]; } // 基于ID的比较器 struct MemberFuncPtrIDLess { bool operator()(Fn lhs, Fn rhs) const { return get_func_id(lhs) < get_func_id(rhs); } }; int main() { A a; B b; Fn fn1 = static_cast<Fn>(&A::a); Fn fn2 = static_cast<Fn>(&B::b); std::map<Fn, Base*, MemberFuncPtrIDLess> functions; functions[fn1] = &a; functions[fn2] = &b; return 0; };
方案3:利用编译器扩展的std::less(非标准但实用)
GCC、Clang、MSVC等主流编译器均支持将std::less用于成员函数指针比较(作为语言扩展)。写法最简单,但需注意这并非C++标准强制要求,跨平台时需确认编译器支持。
#include <map> #include <functional> class Base { public: //... }; class A : public Base { public: bool a(int v) { return v < 10; } }; class B : public Base { public: bool b(int v) { return v > 10; } }; using Fn = bool (Base::*)(int); int main() { A a; B b; Fn fn1 = static_cast<Fn>(&A::a); Fn fn2 = static_cast<Fn>(&B::b); // 使用std::less作为比较器 std::map<Fn, Base*, std::less<Fn>> functions; functions[fn1] = &a; functions[fn2] = &b; return 0; };
内容的提问来源于stack exchange,提问作者Patrick Wright
相关产品推荐
相关产品推荐

