Search code examples
c++member-functionsstdbind

Get address of member function through std::bind?


size_t getAddress(F f) {
    typedef void (fnType)(Ts...);
    fnType ** fnPointer = f.template target<fnType*>();
    if (fnPointer == nullptr) { //Must be member function.
        //Code to get address of member function pointer
    }
    return (size_t)*fnPointer;
}

This function works fine for function pointers, but when I try to throw a bound Member function into the mix everything goes south.

I think this is because I template the function pointer as my normal function pointer type. But with a bound member function through std::bind this conversion fails.

I use this in my comparison operator for finding and removing functions from a vector.

EventObject<Ts...>& operator-=(const F& rhs) {
    int i = 0;
    for (auto const& value : callbacks) {
        if (getAddress(rhs) == getAddress(value)) {
            erase(i);
            break;
        }
        i++;
    }
    return *this;
}

Google has failed me. I also imagine that this function will work for lambdas, sorta. As long as the compiler tries to optimize and combine similar lambda expressions.

So how do I get the address of a member function pointer through bind? Or is there a more optimal way? (Besides naming) Perhaps, should I wrap my function in a macro to store the enumerated type for comparisons instead?

Class information for reference:

template <typename...Ts>
class EventObject{
public:
    typedef std::function<void(Ts...)> F;
    typedef std::vector<F> CallBack;
    Callback callbacks;

Solution

  • You should switch to using std::function instead (update: it turns out you did already). std::function is a general-purpose polymorphic function wrapper that will accept raw function pointers, binds, etc. That way you have a standardized way to compare, which you need to pull off somehow but std::function has ways to inspect the target, etc. : https://en.cppreference.com/w/cpp/utility/functional/function

    Your signature becomes:

    EventObject<Ts...>& operator-=(const std::function<R(Args...)>& rhs) {
    

    Update: the issue with your target extraction is that you provide the signature of a plain function as the template argument - this will not work for the more 'advanced' function objects, binds etc. you have to provide the correct type so that:

    target_type() == typeid(T)

    see https://en.cppreference.com/w/cpp/utility/functional/function/target for more information and some relevant examples