How to pass a std :: function object to a function using a function pointer?

I am trying to interact with a library written in c that uses this familiar pattern:

 void some_c_handler(void(*func)(void*), void* data); 

Now I want to write a C++ shell for this function, which looks like this:

 void my_new_cpp_handler(std::function<void()>&& func) { void (*p)() = foo(func); void* data = bar(func); some_c_handler(p, data); } 

Both some_c_handler and my_new_cpp_handler solve the same problem; they take some kind of function along with some state. But the latter is preferable, since it abstracts most of the implementation details from the user and allows you to simply pass it to the lambda object.

So, my_new_cpp_handler should take the func parameter that it is given, convert it to a function pointer and pass its state to data .

I don’t know enough about the standard or implementation of std::function to know if this is even a reasonable request. Do foo and bar exist?

In other words, I want to pass the state function to the c callback handler without having to manually create my own struct type to pass along with it. Obviously, std::function has already done this for us, so I would like to somehow separate the function pointer from the state and pass it to the c -style handler. Is it possible?

+5
source share
4 answers

Is it possible?

No.

You can wrap the C-style callback in std::function<>... and the compiler issues the code to retrieve the data and handler and calls it. However, the exact code for this will depend on the compiler used by ABI and the standard C ++ library. You cannot magically recover this code specified only for the std::function wrapper.

In addition, an arbitrary std::function... (or lambda) can wrap code other than calling a C-style handler. It should be obvious that using “magically restored” code to extract a C-style handler from such an instance of std::function... cannot be successful.

PS

In other words, I want to pass the state function using the c callback handler without having to manually create my own type of structure to pass along with it. Obviously std::function has already done this for us

So, why don't you just use what std::function has already done for you:

 void my_new_cpp_handler(std::function<void()>&& func) { func(); // calls some_c_handler(p, data) IFF that is what "func" encodes. } 
+7
source

You can create a wrapper function whose purpose is to simply call the std::function callback.

 void some_c_handler(void(*)(void*), void*) {} void std_function_caller(void* fn) { (*static_cast<std::function<void()>*>(fn))(); }; auto make_std_function_caller(std::function<void()>& fn) { return std::make_pair(std_function_caller, static_cast<void*>(&fn)); } void my_new_cpp_handler(std::function<void()>&& func) { const auto p = make_std_function_caller(func); some_c_handler(p.first, p.second); } 
+4
source

If you carefully studied the documentation for this library, you will find that

 void some_c_handler(void(*func)(void*), void* data); 

Calls func , passing it the data argument.

This is a very common design pattern for C libraries that perform a callback function. In addition to the callback function, they also accept an additional opaque pointer, which is not interpreted by the library but blindly passed to func . In other words, the C library calls

  func(data); 

You can use this from C ++ code to pass a regular pointer to any class.

This also includes std::function .

The trick is that in most situations you need to use new :

 auto *pointer=new std::function< function_type >... 

The end result is a pointer that can be passed to the C library along with a pointer to the trampoline function:

 some_c_handler(&cpp_trampoline, reinterpret_cast<void *>(pointer)); 

And the trampoline converts an opaque pointer:

 void cpp_trampoline(void *pointer) { auto real_pointer=reinterpret_cast<std::function< ... >*>(pointer); // At this point, you have a pointer to the std::function here. // Do with it as you wish. 

The only detail you will need to set aside here is to figure out the correct area for the dynamically assigned function pointer to avoid memory leaks.

+4
source

According to this link, the std::function object does not have an accessible member that can provide raw access to the pointer. You should probably define a struct that contains a pointer to a pointer to a function and an object, and a constructor shell that stores the address of the pointer in the structure until your std::struct is built to assign the address stored in the pointer to your C handler parameter.

-2
source

All Articles