Convert C++ function pointer to c function pointer
I am developing a C++ application using a C library. I have to send a pointer to function to the C library.
This is my class:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
Ui::MainWindow *ui;
void f(int*);
private slots:
void on_btn_clicked();
};
This is my on_btn_clicked function:
void MainWindow::on_btn_clicked()
{
void (MainWindow::* ptfptr) (int*) = &MainWindow::f;
c_library_function(static_cast<void()(int*)>(ptfptr), NULL);
}
The C function should get a pointer to a such function : void f(int*). But the code above doesn't work, I cannot succeed to convert my f member function to the desired pointer.
Can anybody please help?
Solution 1:
You can't pass a non-static member function pointer as an ordinary function pointer. They're not the same thing, and probably not even the same size.
You can however (usually) pass a pointer to a static member function through C. Usually when registering a callback in a C API, you also get to pass a "user data" pointer which gets passed back to your registered function. So you can do something like:
class MyClass
{
void non_static_func(/* args */);
public:
static void static_func(MyClass *ptr, /* other args */) {
ptr->non_static_func(/* other args */);
}
};
Then register your callback as
c_library_function(MyClass::static_func, this);
i.e. pass the instance pointer to the static method, and use that as a forwarding function.
Strictly speaking for total portability you need to use a free function declared extern "C"
rather than a static member to do your forwarding (declared as a friend
if necessary), but practically speaking I've never had any problems using this method to interface C++ code with GObject code, which is C callback-heavy.
Solution 2:
You can't pass a function pointer to a non-static member function. What you can do is to create a static or global function that makes the call with an instance parameter.
Here's an example I find useful which uses a helper class with two members: a function wrapper and a callback function that calls the wrapper.
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) { return func(args...); }
static std::function<Ret(Params...)> func;
};
// Initialize the static member.
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
Using this you can store any callable, even non-static member functions (using std::bind
) and convert to a c-pointer using the Callback::callback
function. E.g:
struct Foo {
void print(int* x) { // Some member function.
std::cout << *x << std::endl;
}
};
int main() {
Foo foo; // Create instance of Foo.
// Store member function and the instance using std::bind.
Callback<void(int*)>::func = std::bind(&Foo::print, foo, std::placeholders::_1);
// Convert callback-function to c-pointer.
void (*c_func)(int*) = static_cast<decltype(c_func)>(Callback<void(int*)>::callback);
// Use in any way you wish.
std::unique_ptr<int> iptr{new int(5)};
c_func(iptr.get());
}