我很难理解如何将 this 传递给传递给库的回调函数。该功能需要具有特定的签名。
有问题的库是OCILIB(https://vrogier.github.io/ocilib/doc/html/classocilib_1_1_subscription.html),正在尝试将类函数作为Register()的第4个参数传递。
我可以按以下方式顺利通过
&database::callback // a static function of database
或
[](ocilib::Event &event) // as lambda function
{
}
,但是它无权访问实例变量。我试图像
那样使用它[&](ocilib::Event &event) // as lambda function
{
}
但是签名不匹配,并且出现以下错误
database.cpp: In member function ‘bool dcn::database::watch(std::__cxx11::string)’:
database.cpp:104:44: error: no matching function for call to ‘ocilib::Subscription::Register(ocilib::Connection&, std::__cxx11::string&, ocilib::Subscription::ChangeTypesValues, dcn::database::watch(std::__cxx11::string)::<lambda(ocilib::Event&)>, unsigned int, unsigned int)’
}, (unsigned int) 7778, (unsigned int) 0);
^
In file included from /usr/include/ocilib.hpp:9194:0,
from /home/ai/dcn/include/main.h:17,
from database.cpp:1:
/usr/include/ocilib_impl.hpp:6650:13: note: candidate: void ocilib::Subscription::Register(const ocilib::Connection&, const ostring&, ocilib::Subscription::ChangeTypes, ocilib::Subscription::NotifyHandlerProc, unsigned int, unsigned int)
inline void Subscription::Register(const Connection &connection, const ostring& name, ChangeTypes changeTypes, NotifyHandlerProc handler, unsigned int port, unsigned int timeout)
^~~~~~~~~~~~
/usr/include/ocilib_impl.hpp:6650:13: note: no known conversion for argument 4 from ‘dcn::database::watch(std::__cxx11::string)::<lambda(ocilib::Event&)>’ to ‘ocilib::Subscription::NotifyHandlerProc {aka void (*)(ocilib::Event&)}’
make[1]: *** [database.o] Error 1
功能定义为
static void callback(ocilib::Event &);
需要您的帮助才能解决此问题。预先感谢。
答案 0 :(得分:7)
那是一个可怕的API。任何具有回调功能但又不要求void*
的人都在写我们知道在70年代是个好主意的代码。
您别无选择,只能使用全局状态来分派回您的类。
template<std::size_t N, class R, class...Args>
struct crappy_api_fix{
static std::array< std::function<R(Args&&...)>, N >& table(){
static std::array< std::function<R(Args&&...)>, N > arr;
return arr;
}
template<std::size_t I>
static R call( Args...args ){ return table()[I]( std::forward<Args>(args)... ); }
using sig=R(Args...);
template<std::size_t I=N-1>
static sig* make(std::function<R(Args&&...)> f){
if(!table()[I]){
table()[I]=f;
return &call<I>;
}
if(I==0) return nullptr;
return make< (I-1)%N >(f);
}
template<std::size_t I=N-1>
static void recycle( sig* f ){
if (f==call<I>){
table()[I]={};
return;
}
if (I==0) return;
recycle< (I-1)%N >( f);
}
};
类似的东西。它维护N
个std函数的全局表,并返回一个函数指针,该指针知道要调用哪个std函数。
// up to 50 callbacks alive at once:
using cb_helper = crappy_api_fix<50, void, ocilib::Event &>;
// "stateless" function pointer wrapping a lambda:
void(*f)(ocilib::Event&) = cb_helper::make([&](ocilib::Event &event) {});
// blah is the API class with the Register method. We pass the f from above:
blah->Register(arg1, arg2, f, arg4);
// This might be far away fron the above code:
// we should keep copy of the f; when we have unregistered, we shoukd recyle it:
cb_helper::recycle(f); // when `f` is no longer needed
为错别字致歉,请在我的手机上输入。