我一直在使用带有C ++回调的C库。例如,我有以下方法:
int button(int iconid, const char *label, UIhandler handler);
我可以用作:
button(ICON_COLOR, "Some text", callback);
我现在想要使用C ++成员,但我不能按原样传递它的指针。因此,我有以下基于SO的发现和阅读其他实现的包装代码:
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;
template <class InstanceClass>
UIhandler ofxBluiCptr(InstanceClass * instance, void (InstanceClass::*instanceMethod)(int, UIevent))
{
Callback<void(int, UIevent)>::func = std::bind( instanceMethod, instance, std::placeholders::_1, std::placeholders::_2 );
void (*c_func)(int, UIevent) = static_cast<decltype(c_func)>(Callback<void(int, UIevent)>::callback);
return c_func;
}
我现在可以按如下方式使用C库:
button(ICON_COLOR, "Some text", ofxBluiCptr(this, &ofApp::buttonPressed ))
但是我很难理解。任何人都可以提供这方面的反馈,也许可以评论这种方式是否安全?
答案 0 :(得分:1)
如果我理解正确,你想传递成员函数,为此你需要“绑定”它this
。
有两种简单的方法可以做到这一点。如果你可以得到this
指针,只需创建一个静态包装函数,它将调用该成员,使用这个this
指针。
在更有可能无法执行此操作的事件中,创建一个将捕获this
的lambda,并接受您要传递给CB的参数。使用这个lambda作为你的CB。
auto myCB = [this](auto & param1) { this->member(param1);}
BTW,无论何时看到bind
,都要检查是否使用lambdas创建更简单的代码。在大多数情况下,你会。
这有一个缺点就是它不能用于那里的C风格函数指针。
要解决此问题,您可以使用相关实例包装每个CB。例如:
struct Wrapper{
static CB_instance* instance;
static void myCallback(Param1 p1, Param2 p2) {
instance->callback(p1, p2);
}
现在,Wrapper::myCallback
可以用作C函数指针。
如果您将它变为寺庙,您将获得代码,与您开始使用的代码非常相似......