C++ 如何散列和比较指向成员函数的指针?

C++ 如何散列和比较指向成员函数的指针?,c++,hash,function-pointers,member-function-pointers,C++,Hash,Function Pointers,Member Function Pointers,如何哈希(STD::Hash或Booo::hash)一个C++指针指向成员函数?< /P> 例如: 我有几个bool(类::*functionPointer)((非静态)指向类的几个不同方法,我需要散列这些指向成员函数的指针 我该怎么做 我还可以如何比较(STD::少)那些成员函数指针,以便我可以将它们存储在一个STD::SET/< P>所有C++对象,包括指向成员函数的指针,都在内存中表示为字符数组。所以你可以试试: bool (Class::*fn_ptr)() = &Class::

如何哈希(STD::Hash或Booo::hash)一个C++指针指向成员函数?< /P> 例如:

我有几个bool(类::*functionPointer)((非静态)指向类的几个不同方法,我需要散列这些指向成员函数的指针

我该怎么做


我还可以如何比较(STD::少)那些成员函数指针,以便我可以将它们存储在一个STD::SET/

< P>所有C++对象,包括指向成员函数的指针,都在内存中表示为字符数组。所以你可以试试:

bool (Class::*fn_ptr)() = &Class::whatever;
const char *ptrptr = static_cast<const char*>(static_cast<const void*>(&fn_ptr));

我无法按照前面的回答中所述的方式强制转换指针(在Microsoft编译器2010中),但这对我很有效:

static string fmptostr(int atype::*opt)
  {
      char buf[sizeof(opt)];
      memcpy(&buf,&opt,sizeof(opt));
      return string(buf,sizeof(opt));
  }
关于指针的按位标识,它可以是按位的,所以如果使用了适当的编译器开关,它似乎是按位的。至少对于Microsoft编译器来说是这样的,例如 使用#pragma指针指向#成员
和一个开关…/vmg

如果您的成员函数指针是唯一的,这在大多数基于回调的订阅中都是正确的,那么您可以使用勾号,它的唯一性由程序中类型的唯一性(即
Class::Method
)保证,并且它适合存储在
无序映射中,即

struct MyEvent {

    using fn_t = std::function<void(MyEvent &)>;
    using map_t = std::unordered_map<std::type_index, fn_t>;


    template <typename Handler>
    void subscribe(Object& obj, Handler&& handler) {
        fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
            (obj.*handler)(event);
        }
        std::type_index index = typeid(Handler);
        subscribers.emplace(std::move(index), std::move(fn));
    }

    void fire() {
        for(auto& pair: subscribers) {
            auto& fn = pair.second;
            fn(*this);
        }
    }

    map_t subscribers;
}

所以,上面的示例为您提供了类/方法唯一性,如果您需要对象/方法唯一性,那么您应该有一个提供组合哈希的结构,假设成员函数指针存在
std::hash
,并且已经存在
std::hash

通常没有任何理由对指针进行哈希,因为它直接指向您想要访问的对象。请提供一些代码来说明您的问题。您什么时候会说一个函数指针比另一个函数指针“小”?@bojan:如果比较的唯一目的是将它们存储在排序列表中,那么任何确定性排序都可以。例如二进制值。我有一个类,它有一个成员函数指针作为成员变量。我需要将该类存储在一个std::set和一个std::hash_set中,以便它在该成员函数指针上需要一个hash和一个std::less。除了成员函数指针之外,您的类的每个字段中是否都有相同的实例?如果没有,那么您不需要将其包含在哈希/比较中,这就很好地避免了问题!只有在我的编译器中,我需要一个重新解释的类型转换,而不是静态类型转换。对一些棘手问题的出色处理,+1。我没有想到pmf1==pmf2不一定意味着按位标识。指向成员函数的指针可能包含填充,在比较是否相等时会忽略填充,并且可能具有随机值。散列任何填充字节都会导致散列函数失败。@詹姆斯:我从“问题是成员函数指针的存储表示可能包含不参与值的位”开始讨论,而使用“canoiclised”索引的想法当然很聪明(感谢这个想法!),我想补充一个警告:据我所知,不可能将成员指针与虚拟函数(例如接口/ABC中的函数)进行相等比较。由于相同的“偏移量”实际上可能解析为不同的实现,这取决于绑定成员指针的实际实例。因此,这种方法在这种情况下就失效了。
struct MyEvent {

    using fn_t = std::function<void(MyEvent &)>;
    using map_t = std::unordered_map<std::type_index, fn_t>;


    template <typename Handler>
    void subscribe(Object& obj, Handler&& handler) {
        fn_t fn = [&, handler = std::move(handler)](MyEvent& event) {
            (obj.*handler)(event);
        }
        std::type_index index = typeid(Handler);
        subscribers.emplace(std::move(index), std::move(fn));
    }

    void fire() {
        for(auto& pair: subscribers) {
            auto& fn = pair.second;
            fn(*this);
        }
    }

    map_t subscribers;
}
MyEvent event;
MyObject obj = ...;
event.subscribe(obj, &MyObject::on_event );
...
event.fire();