Usar una función miembro de clase C++ como función de devolución de llamada de C
Tengo una biblioteca C que necesita registrar una función de devolución de llamada para personalizar algún procesamiento. El tipo de función de devolución de llamada es int a(int *, int *)
.
Estoy escribiendo un código C++ similar al siguiente e intento registrar una función de clase C++ como función de devolución de llamada:
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()
{
}
El compilador arroja el siguiente error:
In constructor 'A::A()',
error:
argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’.
Mis preguntas:
- En primer lugar, ¿es posible registrar una función miembro de una clase C++ como estoy intentando hacer y, de ser así, cómo? (Leí 32.8 en http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html . Pero en mi opinión, no resuelve el problema)
- ¿Existe una forma alternativa o mejor de abordar esto?
Puede hacerlo si la función miembro es estática.
Las funciones miembro no estáticas de la clase A tienen un primer parámetro de tipo implícito class A*
que corresponde a este puntero. Es por eso que solo podrías registrarlos si la firma de la devolución de llamada también tuviera el primer parámetro de class A*
tipo.
También puede hacer esto si la función miembro no es estática, pero requiere un poco más de trabajo (consulte también Convertir puntero de función C++ en puntero de función 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) {
return 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;
}
Este ejemplo es completo en el sentido de que compila:
g++ test.cpp -std=c++11 -o test
Necesitarás la c++11
bandera. En el código se ve que register_with_library(func)
se llama, donde func
hay una función estática vinculada dinámicamente a la función miembro e
.