有没有办法使用boost或std bind()所以我可以在C API中使用结果作为回调? 这是我使用的示例代码:
#include <boost/function.hpp>
#include <boost/bind/bind.hpp>
typedef void (*CallbackType)();
void CStyleFunction(CallbackType functionPointer)
{
functionPointer();
}
class Class_w_callback
{
public:
Class_w_callback()
{
//This would not work
CStyleFunction(boost::bind(&Class_w_callback::Callback, this));
}
void Callback(){std::cout<<"I got here!\n";};
};
谢谢!
答案 0 :(得分:3)
不,没有办法做到这一点。问题是C函数指针基本上只是一个指令地址:“转到这个地址,并执行你找到的指令”。 您想要加入函数的任何状态必须是全局的,或者作为参数传递。
这就是为什么大多数C回调API都有一个“context”参数,通常是一个void指针,你可以传入,只是为了让你传入你需要的数据。
答案 1 :(得分:3)
你不能在便携式C ++中这样做。但是,有些库可以创建类似闭包的C函数。这些库在其实现中包含汇编代码,需要手动移植到新平台,但如果它们支持您关心的架构,则它们可以正常工作。
例如,使用Bruno Haible的trampoline库,您可以编写如下代码:
#include <trampoline.h>
class Class_w_callback
{
static Class_w_callback* saved_this;
public:
Class_w_callback()
{
CallbackType cb = (CallbackType) alloc_trampoline((tramp_cb) invoke, &saved_this, this);
CStyleFunction(cb);
free_trampoline(cb);
}
void Callback(){std::cout<<"I got here!\n";};
typedef int (*tramp_cb)(...);
static int invoke() {
Class_w_callback& me = *saved_this;
me.Callback();
return 0;
}
};
请注意,尽管使用了静态成员,但alloc_trampoline
创建的trampolines是可重入的:当调用返回的回调时,它首先将指针复制到指定的地址,然后调用原始函数原始论点。如果代码也必须是线程安全的,那么saved_this
应该是线程本地的。
答案 2 :(得分:1)
这不起作用。
问题是bind
返回一个仿函数,即一个带有operator()
成员函数的C ++类。这不会绑定到C函数指针。您需要的是静态或非成员函数,它将this
指针存储在全局变量或静态变量中。当然,为当前回调找到正确的this
指针可能是一项非常重要的任务。
答案 3 :(得分:0)
正如其他人所提到的,您需要一个全局变量(一个静态成员是一个隐藏为变量成员的全局变量),当然,如果您需要多个对象以在上述回调中使用不同的参数, ,它将无法正常工作。
C库可以提供void *
或类似的上下文。在这种情况下,请使用该功能。
C库可以使用其对象(struct
指针)来调用您的回调。假设您有一个名为example
的库,该库提供了一个名为example_t
的类型,并定义了这样的回调:
callback(example_t *e, int param);
然后,您可以将上下文(也称为this
指针)放在该example_t
结构中,并在回调中将其取回。
假设您只有一个线程使用该特定的C库,并且仅当您在库中调用一个函数时才可以触发回调(即,您不会在某个随机时间点触发事件),您仍然可以使用全局变量。您要做的是在每次调用之前将当前对象保存在全局对象中。像这样:
object_i_am_working_with = this;
make_a_call_to_that_library();
这样,在回调内部,您始终可以访问object_i_am_working_with
指针。在多线程应用程序中或库在后台自动生成事件(例如,按键,来自网络的数据包,计时器等)时,此功能不起作用
在多线程环境中,这是一个有趣的解决方案。如果您没有以前的解决方案,则可以使用线程解决问题。
在C ++ 11中,有一个名为thread_local
的新特殊说明符。在过去,您必须手动处理特定于每个线程实现的问题……现在您可以执行以下操作:
thread_local Class_w_callback * callback_context = nullptr;
然后,在回调中,您可以使用callback_context
作为指向Class_w_callback
类的指针。
当然,这意味着您需要为创建的每个对象创建一个线程。在您的环境中,这可能不可行。就我而言,我的组件都在各自的循环中运行,因此每个组件都有各自的thread_local
环境。
请注意,如果库自动生成事件,则您可能也不会这样做。
如上所述,在过去,您必须自己管理本地线程环境。使用pthread
(基于Linux),您可以通过pthread_getspecific()
访问特定于线程的数据:
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
这利用了动态分配的内存。可能是在Linux下的g ++中实现thread_local
的方式。
在MS-Windows下,您可能会使用TlsAlloc函数。