Question

I suspect this is impossible, but thought I'd ask. Say I have a class with a method:

class A {
public:
    void b(int c);
};

I can make a pointer to that member function:

void (A::*ptr)(int) = &A::b;
(someAInstance.*ptr)(123);

I can also abuse function pointers and make a pointer that takes the A argument directly (I don't know if this is safe, but it works on my machine):

void (*ptr2)(A*, int) = (void (*)(A*, int))&A::b;
(*ptr2)(&someAInstance, 123);

What I want is to somehow curry the A argument, and create a function pointer that just takes an int, but calls the A::b method on a particular A instance I've predefined. The A instance will stay constant for that particular function pointer, but there may be several function pointers all pointing to the same A::b method, but using different A instances. For example, I could make a separate wrapper function:

A* someConstantA = new A;
void wrapper(int c) {
    someConstantA->b(c);
}

void (*ptr3)(int) = &wrapper;

Now I can use ptr3 without knowing which particular A it's dispatching the call to, but I had to define a special function to handle it. I need a way to make pointers for any number of A instances, so I can't hardcode it like that. Is this in any way possible?


Edit: Should've mentioned, I'm trapped in C++03 land, and also can't use Boost

Was it helpful?

Solution

If you have a sufficiently new compiler (e.g. gcc 4.2+), it should include TR1, where you could use std::tr1::bind:

#include <cstdio>
#include <tr1/functional>

class A {
public:
    void b(int c) {
        printf("%p, %d\n", (void*)this, c);
    }
};

int main() {
    A* a = new A;

    std::tr1::function<void(int)> f =
        std::tr1::bind(&A::b, a, std::tr1::placeholders::_1);  // <--
    f(4);

    delete a;

    return 0;
}

It is also doable in pure C++03 without TR1, but also much more messier:

std::binder1st<std::mem_fun1_t<void, A, int> > f =
    std::bind1st(std::mem_fun(&A::b), a);

You could also write your own function objects.

Note that, in all the above cases, you need to be very careful about the lifetime of a since that is a bare pointer. With std::tr1::bind, you could at least wrap the pointer in a std::tr1::shared_ptr, so that it can live just as long as the function object.

std::tr1::shared_ptr<A> a (new A);
std::tr1::function<void(int)> f =
    std::tr1::bind(&A::b, a, std::tr1::placeholders::_1);

OTHER TIPS

Don't create a wrapper function, create a wrapper functor. This allows you to encapsulate whatever state you want to (e.g. an A*) in a callable object.

class A {
public:
    void b(int c) {}
};

struct wrapper {
  A* pA;
  void (A::*pF)(int);
  void operator()(int c) { (pA->*pF)(c); }
  wrapper(A* pA, void(A::*pF)(int)) : pA(pA), pF(pF) {}
};

int main () {
  A a1;
  A a2;

  wrapper w1(&a1, &A::b);
  wrapper w2(&a2, &A::b);

  w1(3);
  w2(7);
}

If you are using C++11, you might use a lambda (untested code):

template<typename T, typename A>
 std::function<void(A)> curry(T& object, void (T::*ptr)(A))
{
  return [](A a) { (object.*ptr)(std::forward<A>(a)); }
}

I'd be using Boost::bind for this.

Basically:

class A
{
    int myMethod(int x)
    {
        return x*x;
    }
};

int main(int argc, char* argv[])
{
    A test();
    auto callable = boost::bind(&A::myMethod, &A, _1);

    // These two lines are equivalent:
    cout << "object with 5 is: " << test.myMethod(5) << endl;
    cout << "callable with 5 is: " << callable(5) << endl;
    return 0;
}

I think that should work. I'm also using auto in here to deduce the type returned by boost::bind() at compile-time, which your compiler may or may not support. See this other question at stackoverflow for an explanation of the return type of bind.

Boost supports back to Visual Studio 2003 (I think) and this all this will work there, though you'll be using BOOST_AUTO I think. See the other question already linked for an explanation.

What you want to do is not possible. To see why, assume that it is possible - the function pointer must point to a function somewhere in your executable or one of its libraries, so it must point to a function that knows which instance of A to call, much like your wrapper function. Because the instance of A is not known until runtime, you'd have to create those functions at runtime, which isn't possible.

What you're trying to do is possible in C++03, as long as you're happy to pass around a function object rather than a function pointer.

As others have already given solutions with C++11 lambdas, TR1 and boost (all of which are prettier than the below), but you mentioned you can't use C++11, I'll contribute one in pure C++03:

int main()
{
    void (A::*ptr)(int) = &A::b;
    A someAInstance;

    std::binder1st<std::mem_fun1_t<void,A,int> > fnObj =
         std::bind1st(std::mem_fun(ptr), &someAInstance);
    fnObj(321);
};

I've worked something out with a template Delegate class.

// T is class, R is type of return value, P is type of function parameter
template <class T, class R, class P> class Delegate
{
    typedef R (T::*DelegateFn)(P);
private:
    DelegateFn func;
public:
    Delegate(DelegateFn func)
    {
        this->func = func;
    }
    R Invoke(T * object, P v)
    {
        return ((object)->*(func))(v);
    }
};

class A {
private:
    int factor;
public:
    A(int f) { factor = f; }
    int B(int v) { return v * factor; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    A * a1 = new A(2);
    A * a2 = new A(3);

    Delegate<A, int, int> mydelegate(&A::B);

    // Invoke a1->B
    printf("Result: %d\n", mydelegate.Invoke(a1, 555));

    // Invoke a2->B
    printf("Result: %d\n", mydelegate.Invoke(a2, 555));

    _getch();
    delete a1;
    delete a2;
    return 0;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top