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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:06:13