简体   繁体   English

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

[英]How to hash and compare a pointer-to-member-function?

How can i hash (std::tr1::hash or boost::hash) a c++ pointer-to-member-function?我如何散列(std::tr1::hash 或 boost::hash)一个 C++ 成员函数指针?

Example:例子:

I have several bool (Class::*functionPointer)() (not static) that point to several diferent methods of the class Class and i need to hash those pointer-to-member-function.我有几个 bool (Class::*functionPointer)() (非静态)指向类 Class 的几个不同方法,我需要散列那些指向成员函数的指针。

How can i do that?我怎样才能做到这一点?

Also how can i compare (std::less) those member function pointers so i can store them in a std::set?另外我如何比较(std::less)那些成员函数指针,以便我可以将它们存储在 std::set 中?

All C++ objects, including pointers to member functions, are represented in memory as an array of chars.所有 C++ 对象,包括指向成员函数的指针,都在内存中表示为字符数组。 So you could try:所以你可以试试:

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

Now treat ptrptr as pointing to an array of (sizeof(bool (Class::*)())) bytes, and hash or compare those bytes.现在将ptrptr视为指向一个(sizeof(bool (Class::*)()))字节数组,并散列或比较这些字节。 You can use unsigned char instead of char if you prefer.如果您愿意,可以使用unsigned char而不是char

This guarantees no false positives - in C++03, pointers to member functions are POD, which means among other things that they can be copied using memcpy.这保证没有误报——在 C++03 中,指向成员函数的指针是 POD,这意味着它们可以使用 memcpy 进行复制。 This implies that if have the same byte-for-byte values, then they are the same.这意味着如果具有相同的字节对字节值,则它们是相同的。

The problem is that the storage representation of member function pointers could include bits which do not participate in the value - so they will not necessarily be the same for different pointers to the same member function.问题是成员函数指针的存储表示可能包括不参与值的位 - 因此对于指向同一成员函数的不同指针,它们不一定相同。 Or the compiler might, for some obscure reason, have more than one way of pointing to the same function of the same class, which are not byte-wise equal.或者编译器可能出于某种晦涩的原因,有不止一种指向同一类的同一函数的方法,这些方法在字节上是不相等的。 Either way you can get false negatives.无论哪种方式,你都可能得到假阴性。 You'll have to look into how member function pointers actually work on your implementation.您必须研究成员函数指针在您的实现中实际是如何工作的。 It must implement operator== for member function pointers somehow, and if you can find out how then you can probably figure out an order and a hash function.它必须以某种方式为成员函数指针实现operator== ,如果您能找出方法,那么您可能会找出顺序和散列函数。

That's potentially hard: member function pointers are awkward, and the storage is likely to include different amounts of non-participating "slack space" according to what kind of function is pointed to (virtual, inherited).这可能很困难:成员函数指针很笨拙,并且根据指向的函数类型(虚拟的、继承的),存储可能包含不同数量的非参与“松弛空间”。 So you'll probably have to interact quite significantly with your compiler's implementation details.因此,您可能必须与编译器的实现细节进行大量交互。 This article might help get you started: http://www.codeproject.com/KB/cpp/FastDelegate.aspx本文可能会帮助您入门: http : //www.codeproject.com/KB/cpp/FastDelegate.aspx

A cleaner alternative might be to do a linear search through an array in order to "canonicalise" all your function pointers, then compare and hash based on the position of the "canonical" instance of that function pointer in your array.更简洁的替代方法可能是对数组进行线性搜索,以便“规范化”所有函数指针,然后根据数组中该函数指针的“规范”实例的位置进行比较和散列。 Depends what your performance requirements are.取决于你的性能要求是什么。 And even if there are requirements, does the class (and its derived classes) have so many functions that the linear search will take that long?并且即使有要求,类(及其派生类)是否具有如此多的函数,以至于线性搜索需要那么长时间?

typedef bool (Class::*func)();
vector<func> canon;

size_t getIndexOf(func fn_ptr) {
    vector<func>::iterator it = find(canon.begin(), canon.end(), fn_ptr);
    if (it != canon.end()) return it - canon.begin();
    canon.push_back(func);
    return canon.size() - 1;
}

If your member function pointer is unique, which is true in most of cases for callback-based subscriptions, then you can use the tick with type_index , which uniqueness is guaranteed by uniqueness of type (ie Class::Method ) in your program, and it is suitable to be stored in unordered_map , ie如果您的成员函数指针是唯一的,这在大多数基于回调的订阅的情况下都是正确的,那么您可以使用带有type_index的勾,该唯一性由您程序中的类型(即Class::Method )的唯一性保证,并且适合存放在unordered_map ,即

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;
}

And the subscription and fire event example:以及订阅和火灾事件示例:

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

So, example above gives you class/method uniqueness, and if you need object/method uniqueness, then you should have an struct, which provides combined hash, assuming that there is std::hash<MyObject> and there is already std::hash<std::type_index> for a member function pointer.所以,上面的例子给你类/方法唯一性,如果你需要对象/方法唯一性,那么你应该有一个结构,它提供组合散列,假设有std::hash<MyObject>并且已经有std::hash<std::type_index>用于成员函数指针。

I could not cast the pointer (in Microsoft compiler 2010)as described in previous answer but this works for me:我无法像之前的答案中描述的那样转换指针(在 Microsoft 编译器 2010 中),但这对我有用:

static string fmptostr(int atype::*opt)
  {
      char buf[sizeof(opt)];
      memcpy(&buf,&opt,sizeof(opt));
      return string(buf,sizeof(opt));
  }

About bitwise identity of the pointer, it can be bitwise so it seems if appropriate compiler switches are used.关于指针的按位标识,它可以是按位的,因此看起来是否使用了适当的编译器开关。 At least this is true for Microsoft compiler Eg using #pragma pointers_to_members and a switch.../vmg至少对于使用 #pragma pointers_to_members 和 switch.../vmg 的 Microsoft 编译器来说,这是正确的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM