vimalloc
vimalloc

Reputation: 4177

Is it possible to save a function (pointer?) into an object?

I have searched for this, but i think i am just making myself more confused.

What I am trying to do save a function pointer in an object and have it be called later in another thread.

What i have been envisioning is a constructor that would take a function pointer and the parameters that will be passed to this function pointer. This object will also have a run() method which will run the said function pointer and a wait_until_completed() method that block until the function has been ran.

The function pointer should is going to be a function from another object if that makes any sense. For example

Foo::*Bar(int);

I have the wait_until_completed() working using pthread_cond_t, but am stuck on this function pointer thing and feel like i am just running around in circles.

Any advice?

EDIT: This is for school (any my general understanding) so third party libraries wont work :/

I felt like i did a very poor job explaining this, to let me give some sample code (excluding all the synchronizing stuff)

class Foo
{
public:
    Foo(void (Bar::*function) (int), int function_param)
    {
        // Save the function pointer into this object
        this->function = &function;

        // Save the paramater to be passed to the function pointer in this object
        param = function_param;
    }

    run()
    {
        (*function)(param);
    }

private:
    // The function pointer
    void (Bar::*function) (int) = NULL;

    // The paramater to pass the function pointer
    int param;
}

This is in a nutshell what i am trying to do. However, im not sure if it is a syntax thing or me being stupid, but i cannot figure out how to actually do this and get it to compile.

Thoughs? And thanks for all the advice so far :)

Upvotes: 5

Views: 8889

Answers (6)

Xeo
Xeo

Reputation: 131799

First, you would want to typedef your function type, making it easier to reuse it and lessen the potential of mistakes.

typedef void (Bar::*function_type)(int);

Now you can use the typedef like this:

Foo(function_type func, int func_param)
    : function_(func)
    , param_(func_param)
{
}

Also, it's a good idea to use the initialization list to initialize member variables (you can find more about initialization lists here).
However, you would still not be able to call the function. Class member functions, also called bound functions MUST be used with an instantiated object, because they are bound to them. Your run function would have to look like this (you also forgot the return type):

void run(Bar* object){
  (object->*function_(param_));
}

It uses the special ->* operator to call member functions via a member function pointer.
Also, you can't initialize most variables directly inside the class (only static integrals constants like a static const int i = 5;). Now you would be able to instantiate a Foo object and call the run function on it.
Here you got a fully compileable example:

#include <iostream>
using namespace std;

class Bar{
public:
    void MyBarFunction(int i){
        cout << i << endl;
    }
};

class Foo
{
public:
    typedef void (Bar::*function_type)(int);

    Foo(Bar* object, function_type function, int function_param)
        : object_(object)  // save the object on which to call the function later on
        , function_(function)  // save the function pointer
        , param_(function_param)  // save the parameter passed at the function
    {
    }


    void Run()
    {
        (object_->*function_)(param_);
    }

private:
    // The object to call the function on
    Bar* object_;

    // The function pointer
    function_type function_;

    // The paramater to pass the function pointer
    int param_;
};

int main(void){
    // create a Bar object
    Bar bar;
    // create a Foo object, passing the Bar object
    // and the Bar::myBarFunction as a parameter
    Foo foo(&bar, &Bar::MyBarFunction, 5);

    // call Bar::MyBarFunction on the previously passed Bar object 'bar'
    foo.Run();

    cin.get();
    return 0;
}

This may be a bit much to digest at once, but I hope this helps you understanding member function pointers and how to use them. :)

Upvotes: 8

Edward Strange
Edward Strange

Reputation: 40859

Everything about your example code is technically correct and should work, with exception to your attempt to assign NULL to a member variable where it's declared. This can only be done with static integrals, and function pointers don't count.

So, remove that line and your example should work just fine from what I can tell.

With that said, you should prefer initializers to assignment in the constructor body. Ergo it should look like so:

Foo(void (Bar::*fun) (int), int fparam) : function(fun), param(fparam) {}

Edit: Oooh, I missed something in your OP. Above you are accepting a pointer to member function as your parameter but attempting to call it as a normal function. Corrected form would be to use void (*)(int) as your type rather than void (Bar::*)(int).

Upvotes: 1

Nim
Nim

Reputation: 33655

Use a boost function object.

EDIT: here is a trivial example:

#include <iostream>
#include <boost/function.hpp>

struct X {
  int foo(int a, int b) { return a * b; }
};

int main(void)
{
  boost::function<int (X*, int, int)> func;
  func = &X::foo;

  X x;
  std::cout << func(&x, 1, 2) <<std::endl;

  return 0;
}

Upvotes: 2

Arafangion
Arafangion

Reputation: 11910

And if you don't take Jerry's advice, I'd suggest using Functors instead of messing about with finicky function pointers.

http://en.wikipedia.org/wiki/Function_object

However, I recommend Jerry's answer.

Upvotes: 0

James McNellis
James McNellis

Reputation: 355069

Yes, you can store a function pointer:

struct simple_callable_object
{
    void (*f_)();
    simple_callable_object(void (*f)()) : f_(f) { }

    void operator()() { f_(); }
};

This pattern is generalized in the polymorphic function wrapper, function, and the argument binder, bind, which can be found in Boost, C++ TR1, and C++0x.

The pattern of running a function asynchronously and later being able to block and wait for it to complete is called a "future." The C++0x Thread Support Library has std::future and std::async which facilitate this task. For example:

// pretend 'f' is a long-running task that you want to run asynchronously:
int f(int x) { return x * 2; }

void g()
{
    std::future<int> fi = std::async(f, 21);

    // do other meaningful work

    int x = fi.get(); // blocks until the async task completes
}

You don't have to use std::async to get a std::future; you could write a thread pool or some other facility that asynchronously completes tasks and have one of them generate and return futures.

Upvotes: 4

Jerry Coffin
Jerry Coffin

Reputation: 490128

It sounds like you're trying to re-invent the "command" pattern. Loki (among many others) should give a reasonable start (though you'll probably have to add the thread synchronization yourself).

Upvotes: 3

Related Questions