2009-08-25 2 views
6

Как я могу хэш (std :: tr1 :: hash или boost :: hash) C++-указатель на функцию-член?Как хэш и сравнить функцию-указатель-член?

Пример:

У меня есть несколько BOOL (класс :: * functionPointer)() (не статический), которые указывают на несколько Diferent методов класса класса и мне нужно хэш те члены-функции указатель на ,

Как я могу это сделать?

Также как я могу сравнить (std :: less) эти указатели на функцию, чтобы я мог хранить их в std :: set?

+7

Обычно нет указаний на хэш-указатель, поскольку он указывает прямо на предмет, к которому вы хотите получить доступ.Укажите код, который иллюстрирует то, о чем вы просите. – 2009-08-25 13:24:48

+0

Когда вы скажете, что один указатель функции «меньше», чем другой? –

+0

@bojan: Если единственная цель сравнения состоит в том, чтобы хранить их в отсортированном списке, любое детерминированное упорядочение будет делать. Например, двоичное значение. – erikkallen

ответ

13

Все объекты C++, включая указатели на функции-члены, представлены в памяти как массив символов. Таким образом, вы можете попробовать:

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

Спасибо, шар * делает трюк! Только в моем компиляторе мне нужен reinterpret_cast вместо static_cast. – AllDayCpp

+1

Отличное обращение с некоторыми из более сложных вопросов, +1. Мне не пришло в голову, что pmf1 == pmf2 не обязательно означает побитовое тождество. –

+0

Указатель на функцию-член может содержать отступы, которые будут игнорироваться при сравнении для равенства и могут принимать случайные значения. Хеширование любых байтов заполнения приведет к сбою хеш-функции. –

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

Смежные вопросы