题
我有一个C库,需要注册一个回调函数来定制一些处理。回调函数的类型是 int a(int *,int *)
。
我正在编写类似于以下内容的C ++代码,并尝试将C ++类函数注册为回调函数:
class A {
public:
A();
~A();
int e(int *k, int *j);
};
A::A()
{
register_with_library(e)
}
int
A::e(int *k, int *e)
{
return 0;
}
A::~A()
{
}
编译器抛出以下错误:
In constructor 'A::A()',
error:
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’.
我的问题:
- 首先是可以像我正在尝试的那样注册C ++类的memeber函数,如果是这样的话? (我在 http://www.parashift上阅读了32.8。 com / c ++ - faq-lite / mixing-c-and-cpp.html 。但在我看来它并没有解决问题)
- 是否有替代/更好的方法来解决这个问题? 醇>
解决方案
如果成员函数是静态的,则可以这样做。
A类的非静态成员函数具有类型 class A *
的隐式第一个参数,它对应于 this 指针。这就是为什么如果回调的签名也有 class A *
类型的第一个参数,你只能注册它们。
其他提示
如果成员函数不是静态的,你也可以这样做,但它需要更多的工作(参见将C ++函数指针转换为c函数指针):
#include <stdio.h>
#include <functional>
template <typename T>
struct Callback;
template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
template <typename... Args>
static Ret callback(Args... args) {
func(args...);
}
static std::function<Ret(Params...)> func;
};
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
void register_with_library(int (*func)(int *k, int *e)) {
int x = 0, y = 1;
int o = func(&x, &y);
printf("Value: %i\n", o);
}
class A {
public:
A();
~A();
int e(int *k, int *j);
};
typedef int (*callback_t)(int*,int*);
A::A() {
Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);
register_with_library(func);
}
int A::e(int *k, int *j) {
return *k - *j;
}
A::~A() { }
int main() {
A a;
}
这个例子在它编译的意义上是完整的:
g++ test.cpp -std=c++11 -o test
您需要 c ++ 11
标志。在代码中,您看到 register_with_library(func)
被调用,其中 func
是动态绑定到成员函数 e
的静态函数。
问题是方法!=功能。编译器会将您的方法转换为类似的东西:
int e( A *this, int *k, int *j );
因此,它确定您无法传递它,因为类实例不能作为参数传递。解决方法的一种方法是将方法设置为静态,这样就可以获得良好的类型。但它不会有任何类实例,也不会访问非静态类成员。
另一种方法是使用第一次初始化的A的静态指针声明一个函数。该函数仅将调用重定向到类:
int callback( int *j, int *k )
{
static A *obj = new A();
a->(j, k);
}
然后你可以注册回调函数。
嗯......如果你在win32平台上总是有令人讨厌的Thunking方式...
这是一个解决方案,但我不建议使用它。
它有一个很好的解释,很高兴知道它存在。
使用成员函数的问题是它需要一个可以作用的对象 - 而且C不知道对象。
最简单的方法是执行以下操作:
//In a header file:
extern "C" int e(int * k, int * e);
//In your implementation:
int e(int * k, int * e) { return 0; }
不隶属于 StackOverflow