Usar una función miembro de clase C++ como función de devolución de llamada de C

Resuelto Methos asked hace 15 años • 8 respuestas

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:

  1. 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)
  2. ¿Existe una forma alternativa o mejor de abordar esto?
Methos avatar Jun 16 '09 17:06 Methos
Aceptado

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.

sharptooth avatar Jun 16 '2009 10:06 sharptooth

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++11bandera. En el código se ve que register_with_library(func)se llama, donde funchay una función estática vinculada dinámicamente a la función miembro e.

Anne van Rossum avatar Apr 23 '2015 07:04 Anne van Rossum