I am first going to solve your problem exactly, then show you the way to solve it in a generic way that will work for many different C APIs.
struct c_api {
void(*f)(void*);
void* ptr;
};
template<class F>
c_api c_api_wrap( F* f ) {
return {
[](void* pv) { (*static_cast<F*>(pv))(); },
f
};
}
this takes a pointer to a std::function (or a lambda, I don't care), and creates a tuple of pointer-to-void and pointer-to-function.
Invoking pointer-to-function on pointer-to-void calls the std::function (or lambda).
This is the generic solution:
template<class Sig>
struct c_api;
template<class R, class...Args>
struct c_api<R(Args...)> {
using fptr = R(*)(void*, Args...);
fptr f = nullptr;
void* ptr = nullptr;
template<class F>
explicit c_api( F* pf ):
f([](void* vptr, Args...args)->R {
return (*static_cast<F*>(vptr))(std::forward<Args>(args)...);
}),
ptr(pf)
{}
};
// not needed unless you want to pass in a non-void returning
// function to a void-returning C API:
template<class...Args>
struct c_api<void(Args...)> {
using fptr = void(*)(void*, Args...);
fptr f = nullptr;
void* ptr = nullptr;
template<class F>
explicit c_api( F* pf ):
f([](void* vptr, Args...args) {
(*static_cast<F*>(vptr))(std::forward<Args>(args)...);
}),
ptr(pf)
{}
};
// wrap a pointer to an arbitrary function object to be consumed
// by a C API:
template<class Sig, class F>
c_api<Sig> c_wrap( F* f ) {
return c_api<Sig>(f);
}
in your case, you want c_wrap<void()>(&some_std_function). From that, you can access .ptr and .f to pass to your C API.
It doesn't manage memory at all.
You can pass additional args or handle return values by changing the void() signature; however, it assumes the void* "self" component is the first argument. A fancier version can support the void* anywhere, but that gets verbose.
In case you are wondering how this works, a stateless lambda can be converted to a functoin pointer, which is what we use in the c_api constructor above.