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

时间:2009-08-25 13:21:58

标签: c++ hash function-pointers member-function-pointers

我如何散列(std :: tr1 :: hash或boost :: hash)一个c ++指向成员函数的指针?

示例:

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

我该怎么做?

另外我如何比较(std :: less)那些成员函数指针,以便我可以将它们存储在std :: set中?

3 个答案:

答案 0 :(得分:13)

所有C ++对象(包括指向成员函数的指针)在内存中表示为chars数组。所以你可以试试:

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

现在将ptrptr视为指向(sizeof(bool (Class::*)()))字节的数组,并对这些字节进行散列或比较。如果您愿意,可以使用unsigned char代替char

这保证没有误报 - 在C ++ 03中,指向成员函数的指针是POD,这意味着可以使用memcpy复制它们。这意味着如果具有相同的逐字节值,则它们是相同的。

问题是成员函数指针的存储表示可能包含不参与值的位 - 因此对于指向同一成员函数的不同指针它们不一定相同。或者,由于某些不明原因,编译器可能有多种方法指向同一个类的相同函数,这些函数在字节方面不相等。无论哪种方式,你都可以得到假阴性。您将不得不研究成员函数指针如何实际对您的实现起作用。它必须以某种方式为成员函数指针实现operator==,如果你能找到如何,那么你可以找出一个顺序和一个哈希函数。

这可能很难:成员函数指针很笨拙,根据指向的函数类型(虚拟,继承),存储可能包含不同数量的非参与“松弛空间”。因此,您可能必须与编译器的实现细节进行非常重要的交互。本文可能会帮助您入门:http://www.codeproject.com/KB/cpp/FastDelegate.aspx

更清晰的替代方法可能是通过数组进行线性搜索,以便“规范化”所有函数指针,然后根据数组中该函数指针的“规范”实例的位置进行比较和散列。取决于您的性能要求。即使有需求,类(及其派生类)是否具有如此多的函数,线性搜索将花费那么长时间?

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

答案 1 :(得分:0)

我无法按照上一个答案中的说明转换指针(在Microsoft编译器2010中),但这对我有用:

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

关于指针的按位标识,它可以是按位的,所以看起来如果使用了适当的编译器开关。至少对于Microsoft编译器来说是这样 使用#pragma pointers_to_members 和一个开关...... / vmg

答案 2 :(得分:0)

如果您的成员函数指针是唯一的,这在大多数情况下对于基于回调的订阅都是如此,那么您可以在type_index中使用对号,该唯一性由类型的唯一性(即{{1 }}),并且适合存储在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;
}

因此,上面的示例为您提供类/方法的唯一性,如果您需要对象/方法的唯一性,那么您应该有一个结构,该结构提供组合的哈希,并假设存在MyEvent event; MyObject obj = ...; event.subscribe(obj, &MyObject::on_event ); ... event.fire(); 并且已经存在{{ 1}}用于成员函数指针。