标题有点误导,但我不知道如何在一行中说出问题。
基本上,我使用的是具有此类定义的库:
class UCallbackWrapper {
public:
virtual UCallbackAction operator ()(const UMessage &)=0;
virtual ~UCallbackWrapper() {}
};
我正在使用具有此声明的库的函数:
UCallbackID setCallback(UCallbackWrapper & callback, const char * tag);
基本上,它接收UCallbackWrapper
类型的对象作为参数(引用)。
如果在带有程序主函数的c ++文件中我使用正确的原型声明了一个函数,它允许我将它传递给setCallback
函数,如下所示:
UCallbackAction onImageCallback(const UMessage &msg)
{
// Some code here
}
int main(int argc, char *argv[])
{
setCallback(onImageCallback, "something"); // This works
}
现在,我想创建一个类,并在该类中使用setCallback函数,传递一个属于该类成员的函数。但是,如果我这样做,那么函数的原型来自
UCallbackAction onImageCallback(const UMessage &msg)
到
UCallbackAction (myClass::*)onImageCallback(const UMessage &msg)
我无法再将其传递给setCallback。
我尝试创建一个lambda函数,如下所示:
std::function<UCallbackAction(const UMessage &)> onImageCallback = [&] (const UMessage &msg) -> UCallbackAction {
// Code here
};
setCallback(onImageCallback, "something");
但仍然不起作用,编译器说:
错误:没有匹配函数来调用'USyncClient :: setCallback(std :: function&amp;,const char [8])' 注意:参数1从'std :: function'到'UCallbackWrapper&amp;'没有已知的转换
所以,我考虑创建一个继承自UCallbackWrapper并实现虚方法的类(有点像我在Java中所做的那样),但我不知道如何在C ++中实现(或者可能)。
你能帮助我吗?或者也许指出一些我正在使用lambda函数做错的事情,或者反正的解决方法。答案 0 :(得分:2)
template<class F>
struct UCallbackWrapperImpl:UCallbackWrapper {
F f;
virtual UCallbackAction operator ()(const UMessage & m)final override{
return f(m);
}
};
using upUCallback=std::unique_ptr<UCallbackWrapper>;
template<class F>
upUCallback MakeUCallback(F&& f){
return upUCallback(new UCallbackWrapperImpl<std::decay_t<F>>{std::forward<F>(f)});
}
将lambda传递给MakeUCallback
并获得指向UCallbackWrapper
的智能指针。
MakeUCallback
重新调整指向api所期望的接口的智能指针。将此智能指针存储在回调的生命周期中。它将在最终超出范围时删除回调对象 - 您可以通过std::move
将其扩展到另一个upUCallback
。
要使用api,请取消引用返回的upUCallback
。
请注意,api很奇怪,因为它将引用带到纯虚拟接口。我不知道这些api设计师在做什么,这不是一个好兆头。您可能需要调查api在UCallbackWrapper
类中期望的生命周期管理:它们应该持续多长时间,谁删除它们等等。
在C ++中,您应该始终了解对象生存期要求。
答案 1 :(得分:2)
只需编写一个实现虚函数的类。您还可以将其自身注册为回调。
class MyCallback : public UCallbackWrapper {
public:
UCallbackAction operator ()(const UMessage& message) override {
// Some code here...
}
void registerAsCallback() {
setCallback(*this, "something");
}
};
请注意,由于库API的设计,您有责任在库可能正在使用它时确保您的课程的生命周期:
int main() {
MyCallback mcb;
mcb.registerAsCallback();
// Cause library to use callback here...
}