I need to store callback functions from opencl to later execution, e.g:
void pfn_notify(const char *errinfo, const void *private_info, size_t cb, void *user_data){
fprintf(stderr, "OpenCL Error (via pfn_notify): %s\n", errinfo);
}
These callback functions vary, so I would like to unify storing method and store pointers to them in some kind of container(vector
, map
etc.). In addition some of the arguments needs to be passed after storing instead of binding in the moment of pushing into container.
General pseudocode scheme:
...some code in main... Client.storecallback(function_to_store(some_arguments)); ...rest code in main... class Client{ void storecallback(void*(*)(some_arguments) function){ callback_thread.store(function); callback_thread.start(); } CallbackThread callback_thread; }; class CallbackThread() { void start(){ /* make connection via tcp/ip */ receive(); } void store(void*(*) function){ callback.store(key, function); } void receive() { Buffer* input = new Buffer(tcp_socket); int a = input->pull(); char b = input->pull(); callback.raise(key, a, b); } Callback callback; }; class Callback { std::map<uint64_t key, void*(*) function> callback_map; void store(void*(*) function){ callback_map[key] = function; } template<typename... Args> void raise(uint64_t key, Args... rest_of_arguments){ callback_map[key](rest_of_arguments); } };
I am aware that i need extra class for unification, some kind of Functor
class.
With use of
std::function
andstd::bind
I am able to unificate stored variable type tostd::function<void()>
however, I can not change/bind new arguments to callback functions. This solution requries universalstruct
which will store pointers to arguments variables and replace/fill them with data before calling stored function and I have no idea how to create such an universal structure other than structure templates for each of callback function which is not really nice solution for me.With assist of this Indicies, and this Stackoverflow I was able to create solution in which I can unificate creation process with placeholders which allows me to add some arguments in moment of calling, not only storing:
namespace project_name { namespace detail { template<int I> struct placeholder {}; } } namespace std { template<int I> struct is_placeholder< project_name::detail::placeholder<I> > : std::integral_constant<int, I>{}; } namespace project_name { namespace detail { template <size_t... Is> struct indices {}; template <size_t N, std::size_t... Is> struct build_indices : build_indices<N - 1, N - 1, Is...> {}; template <size_t... Is> struct build_indices<0, Is...> : indices<Is...> {}; template<std::size_t... Is, class F, class... Args> inline auto easy_bind(indices<Is...>, F const& f, Args&&... args) -> decltype(std::bind(f, std::forward<Args>(args)..., placeholder<Is + 1> {}...)){ return std::bind( f, std::forward<Args>(args)..., placeholder<Is + 1> {} ...); } } class Functor { public: template<class R, class... FArgs, class... Args> Functor(std::function<R(FArgs...)> f, Args&&... args) {} template<class R, class... FArgs, class... Args> static inline auto easy_bind(std::function<R(FArgs...)> f, Args&&... args) -> decltype(detail::easy_bind( detail::build_indices<sizeof...(FArgs) - sizeof...(Args)> {}, f, std::forward<Args>(args)...)) { return detail::easy_bind( detail::build_indices<sizeof...(FArgs) - sizeof...(Args)> {}, f, std::forward<Args>(args)...); } }
Unfortunately now I have no clue how to unify storing this, as returned types are different when using std::placeholder
.
Here are my questions then:
- Which of these two approaches is better and how to solve problems of this approach.
- Maybe there is other approach which I should consider but did not think of due to lack of knowledge.
EDIT: Your comments with links to threads about problems not even close to mine are absolutely not useful. Read what question is about before linking something that I have already implemented and inserted into my question. Solved it anyway, I'll add solution for further generations soon.