How to Hash and Compare a Pointer-To-Member-Function

How to hash and compare a pointer-to-member-function?

All C++ objects, including pointers to member functions, are represented in memory as an array of chars. 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. You can use unsigned char instead of char if you prefer.

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. 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.

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

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

How to compare member pointer functions for equality with DLLs involved in Microsoft Visual C?

Comparing pointers (whether they are to member functions, member variables or anything else) will only tell you if the pointer points to the same thing or not - not if they are pointing at "different instances of the same thing that have the same properties". Since a member function of the "EXE's" class A can not possibly be the same function as the "DLL's" class A, since they are different implementations of a class called the same name, you can't expect the pointers to be the same. And no, there is no real way that you can solve that. You could compare the "contents" of the function, and see if the code is the same, but that requires knowing the length of the function, which is not an easy feat.

C++ How can I use an unordered_map with custom hash & compare as member variable if those functions get passed in Constructor?

Considering the fact that you have tagged your Q with C++14, I will post my answer with std::functions instead of function pointers. You can write your class C like this:

using hash_t = std::function<size_t(const struct MyStruct &t1)>;
using comp_t = std::function<bool(const struct MyStruct &t1, const struct MyStruct &t2)>;

class C
{
private:
std::unordered_map<struct MyStruct, int, hash_t, comp_t> map;

public:
C(int bucket_size, hash_t hasher, comp_t comper) :
map(bucket_size, hasher, comper)
{
}
};

and then instantiate your class with the required parameters. See the live demo here.

C++ Converting function pointer to unique “hash” key

The second isn't legal: formally, you cannot convert a pointer to a
function to a pointer to data (and a void* is a pointer to data).
Also, you're not guaranteed to be able to convert any pointer into an
int; the conversion is only legal if int is at least as large as a
pointer (which means that your code should fail to compile on most 64
bit systems).

There are several ways around this. First, on most (all?) modern
machines, poitners to functions and pointers to data do have the same
size and representation. (Posix requires it, in fact. Even if it
wasn't the case on the first Unix machines I used.) If we assume this,
you can guarantee a large enough integral type by using intptr_t, and
"trick" the compiler using an additional level of indirection:

std::pair<intptr_t, intptr_t>(
reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( object ) ),
reinterpret_cast<intptr_t>( reinterpret_cast<void*&>( method ) ) )

(This supposes that object and method are your pointers to the
object and the function.)

Note that this does not work for pointers to member functions.
Pointer to member functions are completely different beasts, and I don't
think that there is any effective way to use them as a key in this way
(since they may, and often do, contain padding, or unset fields, in
certain cases).

For that matter, formally, this isn't really guaranteed even for normal
pointers. The standard allows pointers to have don't care bits, or for
several different pointer representations to compare equal. In
practice, however, it is safe on most (all?) modern machines.

Issue with C++ map using member function pointers as keys

The error is telling you all you need to know:

invalid operands of types ‘int (MyClass::* const)()’ and ‘int (MyClass::* const)()’ to binary ‘operator<’

You cannot compare member function pointers using standard operator<, so you must provide a custom comparator when declaring your map.

Unfortunately, pointers to member functions cannot be compared for inequality, so you cannot define a comparison operator or use a std::mapin this case. I suggest using std::unordered_map, which only needs a std::hash and equality comparison, which you can do. See here for hashing and here for equality comparison.

Unable to Use Specialization of std::hash for Pointer-to-Member?

The trouble is that pointers to member are not really pointers; they just happen to have a similar name and kind of similar syntax. std::hash is specialized for ordinary pointers, but not for pointers to members. You could of course specialize it yourself, but if there's a way to do that that's guaranteed to be safe, I'm not seeing it; there's not much you can do with a pointer to member other than dereference it or cast it to other pointers to members.



Related Topics



Leave a reply



Submit