Использование функции-члена класса C ++ в качестве функции обратного вызова C
Вопрос
У меня есть библиотека 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*)’.
Мои вопросы:
<Ол>Решение
Это можно сделать, если функция-член является статической.
Нестатические функции-члены класса 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 ...
Thunking в Win32: упрощение обратных вызовов для нестатических функций-членов р>
Это решение, но я не рекомендую его использовать.
У этого есть хорошее объяснение, и приятно знать, что оно существует.
Проблема с использованием функции-члена заключается в том, что ей нужен объект, с которым нужно действовать, а C не знает об объектах.
Самый простой способ - сделать следующее:
//In a header file:
extern "C" int e(int * k, int * e);
//In your implementation:
int e(int * k, int * e) { return 0; }