English 中文(简体)
C++ Using Class Method as a Function Pointer Type
原标题:

In a C lib, there is a function waiting a function pointer such that:

lasvm_kcache_t* lasvm_kcache_create(lasvm_kernel_t kernelfunc, void *closure)

where lasvm_kernel_t is defined as:

typedef double (*lasvm_kernel_t)(int i, int j, void* closure);

Now, if I send a method defined in a class to lasvm_kcache_create:

double cls_lasvm::kernel(int i, int j, void *kparam)
...
lasvm_kcache_t *kcache=lasvm_kcache_create(&kernel, NULL);

I get: "cannot convert ‘double (cls_lasvm::)(int, int, void)’ to ‘double ()(int, int, void)’"

What should I do?

问题回答

I m assuming that the closure argument is a context cookie for the use of the callback to get appropriate context. This is a acomon idiom for callback functions, and seems to be what s going on based on the snippets you ve provided (but I don t know for sure, as I don t know anything about kcache_create() except what you posted here).

You can use that cookie to pass a pointer to the cls_lasvm instance you re dealing with like so:

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);

If I m wrong about closure being a context cookie, then your callback function in the cls_lasvm class needs to be static:

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);

Note that a C callback function implemented in C++ must be extern "C". It may seem to work as a static function in a class because class-static functions often use the same calling convention as a C function. However, doing that is a bug waiting to happen (see comments below), so please don t - go through an extern "C" wrapper instead.

If closure isn t a context cookie and for some reason cls_lasvm::kernel() can t be static then you need to come up with a way to stash a this pointer somewhere and retrieve that pointer in the lasvm_kcache_create_callback() function, similar to the way I did in my first example, except that pointer has to come dfrom some mechanism you devise yourself. Note that this will likely make using lasvm_kcache_create() non-reentrant and non-threadsafe. That may or may not be a problem depending on your specific circumstances.

Every C++ member function has an implicit, hidden, first parameter, this.

So the method double cls_lasvm::kernel(int i, int j, void* kparam) is really: double cls_lasvm::kernel(cls_lasvm* this, int i, int j, void* kparam), and it is inappropriate/impossible to use it as a function-pointer parameter.

To make progress, convert your method to be a static-member-method. That will remove the this pointer. You may still have other issues to overcome, but that is a good start.

If it is an external C library whose code you can not modify, then there is not much you can do about it. You ll not be able to call the member function as they require this pointer to work properly (to get the attributes of the object). The easiest workaround, I can think of is using third void* param to pass around this pointer. You can define struct like after defining one more typedef like:

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;
};

I haven t compiled it, I hope it makes sense.

Then in your class define a static method which receives the call from library:

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);
  }
};

While calling you should use something like:

cls_lasvm a;
MyParam param;
param.pThis = &a;
param.pMemFun = &cls_lasvm::kernel;
param.kParam = NULL;

lasvm_kcache_create(&cls_lasvm::test,&a);




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签