Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Passing a non-static method or std::function<void(…)> as a void (*) argument

I’m trying to define a function/method (void MyClass::myDispatcher(int, int, void *) or std::function<void(int, int, void *)> myDispatcher) which would be a member of a host class.

However, I also need to pass this function to through an external library which takes as argument: void (*dispatcher) (int, int, void *).

Is there a way I can convert a non-static function to the required void (*)(int, int, void *) type ?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

My first attempt with the candidate void MyClass::myDispatcher(int, int, void *) was using the std::bind() in order to bind MyClass::myDispatcher with this. Although I could not convert the return type of std::bind to match the void (*).

The second attempt was done using std::function<void(int, int, void *)> myDispatcher for which I tried to use the reinterpret_cast<void (*)(int, int, void *)>(&myDispatcher) to fit in the requested argument. It did compile but I ultimatly ended up in a segfault within the external library.

I could summarized my two attempts with this example:

class MyClass{
  MyClass() = default;
  
  void myDispatcher(int, int, void *){
    // do something
  }

  void init(){
    myFct = [this](int, int, void*){
      // do something
    };
    
    external_function(reinterpret_cast<void (*)(int, int, void *)>(&myFct));

    // or the non-compiling
    // external_function(std::bind(&MyClass::myDispatcher, this));
  }

private:
  std::function<void(int, int, void*)> myFct;

};

Edit:

As some of you pointed out: this C-style external_function has an extra void * argumement which is passed as the last arg to the provided function!

To summarise: there is no way to do such a thing since there is a fundamental difference between a function pointer and non-static member functions. However, C-style library usually provides a workaround which performs a callback to the provided static function:

void external_function(void (*dispatcher) (int, int, void *), void* info){
  // a bunch of instructions (meaningless for this example)
  
  int a,b;

  dispatcher(a,b,info);
}

Once we know that, one can cast back the info pointer to the class we want.

>Solution :

As stated, this is not possible since there is no way to meaningfully construct a plain function pointer from a (non static) method, a closure, or a std::function object.

Roughly speaking, each of the constructs above are logically formed by two parts: some fixed code (a pointer to a fixed, statically known function), and variable data (the object at hand, or the captures for a closure). We can not simply throw away the second part.

That being said, I would recommend to check if the library will call the dispatcher passing a user-defined pointer for its void * argument. It’s somewhat common to see C style library functions like

void register_callback(void (*dispatcher)(int,int,void *), void *user_data);

This is a trick to allow to simulate closures in C, passing the two "parts" of the closure separately.

If that’s the case, instead of

// not working, just for example
std::function<void(int, int)> f;
register_callback(f);

You can write

// Make sure f will live long enough.
// I'm using new to stress the point, but you can use anything
// else provided that the pointer will be valid when f is
// called.
std::function<void(int, int, void *)> *pf = new ...;
register_callback(call_the_function, pf);

provided you have defined

// fixed function, independent from the std::function object
void call_the_function(int x, int y, void *p) {
   std::function<void(int,int,void*)> *pf =
      (std::function<void(int,int,void*)>*) p;
   (*pf)(x,y);
}

If you used new to keep the pointer valid long enough, remember to delete it when the callback is no longer needed.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading