2

I'm trying to pass any generic function as an argument in a C++ function. As an extra layer of fun, the function is going to reside in its own separate class. In this particular case, they will all take no arguments and return void. This includes members of any generic class.

My current code reads like:

class functionsFedHere {
public:
    void (*callback)();
    functionsFedHere(void(*)());
}

functionsFedHere::functionsFedHere (void(*callbackFunction)()) {
    callback = callbackFunction;
}

void fn1() { cout<<"Fn1"<<endl; }

class myClass {
public:
    int i;
    void fn2() { cout<<i<<endl; }
}

class myOtherClass {
public:
    string j;
    void fn3() { cout<<j<<endl; }
}

int main() {

    // Initialise some objects
    myClass b;
    b.i = 2;

    myOtherClass c;
    c.j = "some text";

    // Works fine with non-member functions
    functionsFedHere objectA(fn1);
    objectA.callback();

    // Doesn't work with member functions
    functionsFedHere objectB(b.fn2);
    functionsFedHere objectC(c.fn3);
}

I've seen solutions like a forwarding function, or boost::bind, but as far as I can tell, I don't think these solutions will fit?

It's also worth noting that eventually I'd like to pass member functions by way of an array of pointers. For example, if myPointer[] is an array of pointers to objects of class myClass, then it would be nice to be able to write something like:

functionsFedHere objectD(myPointer[0]->fn2);

EDIT: Apparently I wasn't clear enough. This answer is not an appropriate answer, because I'm looking to pass both member and non-member functions as arguments (whereas the suggested answer is setting up a member pointer to a function that is a member of the same class).

I don't think that the forward function example will work, because the forwarding function assumes a single class type, where I'd like to pass an object of generic class.

boost::bind could well be the answer; I'm just unfamiliar with it. Can anyone point me towards some newbie-friendly reading material?

EDIT 2: Sorry, forgot to mention I'm programming on a device that is pre-C++11.

Community
  • 1
  • 1
Alec
  • 2,432
  • 2
  • 18
  • 28
  • 3
    _"I don't think these solutions will fit?"_ Why?? – πάντα ῥεῖ Sep 03 '14 at 11:03
  • boost::bind is the solution, unless you can define the functions myClass::fn2 and myOtherClass::fn3 as static. – pragnesh Sep 03 '14 at 11:06
  • @πάνταῥεῖ Original post has been edited to clarify why the suggested solution is not the answer. – Alec Sep 03 '14 at 13:02
  • @Alec I'd say you can use the `boost` solution likewise for pre-C++11 compilers. Otherwise you'll need to brew your own stuff as proposed in the answer here. `myPointer[0]->fn2` simply doesn't yield a member function pointer, and never will, period! And that's what's explained in detail in the duplicate. – πάντα ῥεῖ Sep 03 '14 at 14:03

1 Answers1

5

Use std::function:

class functionsFedHere {
public:
    typedef std::function<void()> Func;
    Func callback;
    functionsFedHere(Func callback_) : callback(callback_) {}
};

void fn1() { cout<<"Fn1"<<endl; }

class myClass {
public:
    int i;
    void fn2() { cout<<i<<endl; }
};

class myOtherClass {
public:
    string j;
    void fn3() { cout<<j<<endl; }
};

class callableClass {
public:
    void operator()() { std::cout << "in callableClass" << std::endl; }
};

int main() {

    // Initialise some objects
    myClass b;
    b.i = 2;

    myOtherClass c;
    c.j = "some text";

    // Works fine with non-member functions
    functionsFedHere objectA(fn1);
    objectA.callback();

    // Works with member functions now
    functionsFedHere objectB(std::bind(&myClass::fn2, b));
    objectB.callback();
    functionsFedHere objectC(std::bind(&myOtherClass::fn3, c));
    objectC.callback();

    // Works with lambdas as well
    functionsFedHere objectLambda([]() { std::cout << "in lambda" << std::endl; });
    objectLambda.callback();

    // Works also with classes with overloaded operator()
    functionsFedHere(callableClass()).callback();
    return 0;
}
Anton Savin
  • 40,838
  • 8
  • 54
  • 90
  • Show a use of lambdas with one of those member functions and you'll earn an upvote from me. – Puppy Sep 03 '14 at 11:21
  • @AntonSavin this looks like a beautiful solution, but I forgot to mention that I'm pre-C++11. – Alec Sep 03 '14 at 13:00
  • @Alec in that case you can use `boost::function` together with `boost::bind` - it's essentially the same. – Anton Savin Sep 03 '14 at 13:02