【发布时间】:2018-12-08 19:11:35
【问题描述】:
我需要将 opencl 中的回调函数存储到以后执行,例如:
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);
}
这些回调函数各不相同,所以我想统一存储方法并将指向它们的指针存储在某种容器中(vector、map 等)。此外,有些参数需要在存储后传递,而不是在推入容器时进行绑定。
-
通用伪代码方案:
...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); } };
我知道我需要额外的课程来统一,某种Functor 课程。
使用
std::function和std::bind我可以将存储的变量类型统一为std::function<void()>但是,我无法更改/绑定新参数到回调函数。这个解决方案需要通用struct,它将存储指向参数变量的指针并在调用存储函数之前用数据替换/填充它们,我不知道如何为每个回调函数创建这样的通用结构而不是结构模板,这不是真的对我来说很好的解决方案。-
在Indicies 和Stackoverflow 的帮助下,我能够创建解决方案,在该解决方案中我可以将创建过程与占位符统一起来,这允许我在调用时添加一些参数,而不仅仅是存储:
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)...); } }
不幸的是,现在我不知道如何统一存储它,因为使用 std::placeholder 时返回的类型不同。
这是我的问题:
- 这两种方法中哪一种更好,以及如何解决这种方法的问题。
- 也许我应该考虑其他方法,但由于缺乏知识而没有想到。
编辑: 你的 cmets 链接到关于问题的线程甚至不接近我的问题是绝对没有用的。在链接我已经实现并插入到我的问题中的内容之前,请阅读问题是关于什么的。无论如何都解决了,我会尽快为后代添加解决方案。
【问题讨论】:
-
听起来你想要独特的
std::function签名和捕获 lambda 函数。 -
问两个 C++ 开发者哪两种方法更好,你会得到三个答案和四个替代方案。
-
对于每个投反对票的人,请让我知道您认为这个问题有什么不对,因为我不知道。
-
另一种选择可能是继承具有
virtual void operator()()函数的抽象基类的类。该函数调用运算符可以在子类中实现,以使用所需的任何参数调用它需要的任何其他函数。并且参数可以是通过构造函数初始化的子类中的成员。