samedi 31 janvier 2015

c++: portable solution to cast and compare member-function pointers

Before I ask what I want to know, here's a little background: I'm wrapping a std::function in my own class Function, which stores some additional data along with the std::function object. Later on, I have a std::vector<Function<Signature>> that stores a whole bunch of Function's of the same signature (e.g. void(int)). These std::function's may represent normal free functions, functors, or member functions that have been bound to an object using std::bind.


At some later point, I want to traverse the std::vector, and check some properties of the Function objects. For example, I want to select every Function that is bound to a particular member-function (regardless of the object it will be called on). This means I have to find a way to store these member-function pointers, while discarding their exact type. In other words, I need to be able to store a pointer of type void (A::*)() and another pointer of type void (B::*)() in the same field.


I used to do this using a union to 'cast' the member-function-pointer to a void*, but then found out that member-function-pointers are implementation-defined and don't have the same size as pointers. Now I'm looking for a portable solution, and this is what I came up with:



class MemFunPtr
{
friend bool operator==(MemFunPtr const &lhs, MemFunPtr const &rhs);

enum { SIZE = sizeof(void(MemFunPtr::*)()) };
char buf[SIZE];

public:
template <typename T, typename R, typename ... Args>
MemFunPtr(R (T::*ptr)(Args ...))
{
union
{
R (T::*memfcn_)(Args ...);
char buf_[SIZE];
} caster;

caster.memfcn_ = ptr;
memcpy(buf, caster.buf_, SIZE);
}
};

bool operator==(MemFunPtr const &lhs, MemFunPtr const &rhs)
{
return memcmp(lhs.buf, rhs.buf, MemFunPtr::SIZE) == 0;
}


Now my question is, if this is portable. I would be even more happy with a more straightforward way of doing this. I looked in to std::mem_fn, but it seems that the type of these objects is unspecified (the examples on cppreference.com use auto), so I don't think this is where the solution lies.


Aucun commentaire:

Enregistrer un commentaire