在C lib中,有一个等待函数指针的函数:
lasvm_kcache_t* lasvm_kcache_create(lasvm_kernel_t kernelfunc, void *closure)
其中lasvm_kernel_t定义为:
typedef double (*lasvm_kernel_t)(int i, int j, void* closure);
现在,如果我将类中定义的方法发送到lasvm_kcache_create:
double cls_lasvm::kernel(int i, int j, void *kparam)
...
lasvm_kcache_t *kcache=lasvm_kcache_create(&kernel, NULL);
我得到:“无法将'double(cls_lasvm :: )(int,int,void )'转换为'double()(int,int,void ) ““
我该怎么办?
答案 0 :(得分:5)
我假设closure
参数是一个上下文'cookie',用于使用回调来获取适当的上下文。这是一个用于回调函数的acomon习语,似乎是根据你提供的片段进行的(但我不确定,因为我对kcache_create()
一无所知,除了你发布在这里)。
您可以使用该cookie将指针传递给您正在处理的cls_lasvm
实例,如下所示:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// have to get a cls_lasvm pointer somehow, maybe the
// void* clpsure is a context value that can hold the
// this pointer - I don't know
cls_lasvm* me = reinterpret_cast<cls_lasvm*>( closure);
return me->kernel( i, j)
}
class cls_lasvm //...
{
...
// the callback that's in the class doens't need kparam
double cls_lasvm::kernel(int i, int j);
};
...
// called like so, assuming it's being called from a cls_lasvm
// member function
lasvm_kcache_t *kcache=lasvm_kcache_create(&lasvm_kcache_create_callback, this);
如果我关闭闭包是一个上下文cookie,那么cls_lasvm
类中的回调函数需要是静态的:
extern "C"
double
lasvm_kcache_create_callback( int i, int j, void* closure)
{
// if there is no context provided (or needed) then
// all you need is a static function in cls_lasvm
return cls_lasvm::kernel( i, j, closure);
}
// the callback that's in the class needs to be static
static double cls_lasvm::kernel(int i, int j, void* closure);
请注意,在C ++ 中实现的C回调函数必须为extern "C"
。它似乎在类中作为静态函数工作,因为类静态函数通常使用与C函数相同的调用约定。但是,这样做是一个等待发生的错误(请参阅下面的评论),所以请不要 - 转而使用extern "C"
包装。
如果closure
不是上下文cookie,并且由于某种原因cls_lasvm::kernel()
不能是静态的,那么你需要想出一种方法来隐藏某个this
指针并检索lasvm_kcache_create_callback()
函数中的那个指针,类似于我在第一个例子中所做的那样,除了指针必须来自你自己设计的一些机制。请注意,这可能会使lasvm_kcache_create()
使用非重入和非线程安全。根据您的具体情况,这可能是也可能不是问题。
答案 1 :(得分:0)
每个C ++成员函数都有一个隐含的隐藏的第一个参数this
。
所以方法double cls_lasvm::kernel(int i, int j, void* kparam)
确实是:
double cls_lasvm::kernel(cls_lasvm* this, int i, int j, void* kparam)
,将它用作函数指针参数是不合适/不可能的。
要取得进展,请将您的方法转换为静态成员方法。这将删除this
指针。您可能仍有其他问题需要克服,但这是一个良好的开端。
答案 2 :(得分:0)
如果它是一个你无法修改其代码的外部C库,那么你无能为力。您将无法调用成员函数,因为它们需要this
指针才能正常工作(以获取对象的属性)。我能想到的最简单的解决方法是使用第三个void*
参数来传递this
指针。您可以在定义一个更多的typedef之后定义struct,如:
typedef double (cls_lasvm::*lasvm_kernel_t_member)(int i, int j, void* closure);
struct MyParam
{
A* pThis;
lasvm_kernel_t_member pMemFun;
void* kParam;
};
我没有编译它,我希望它有意义。
然后在你的类中定义一个静态方法,它接收来自库的调用:
class cls_lasvm
{
static double test(int i, int j, void *kparam)
{
MyParam* pParam = reinterpret_cast<MyParam*>(kparam);
return (pParam->*pMemFun)(i,j,pParam->kParam);
}
};
在打电话时你应该使用类似的东西:
cls_lasvm a;
MyParam param;
param.pThis = &a;
param.pMemFun = &cls_lasvm::kernel;
param.kParam = NULL;
lasvm_kcache_create(&cls_lasvm::test,&a);