2010-01-04 23 views
7

Estoy trabajando en la configuración de una función miembro como devolución de llamada para una biblioteca C que estoy usando. El C-biblioteca establece devoluciones de llamada de esta manera:Función de miembro de clase como devolución de llamada utilizando boost :: bind and boost :: function

typedef int (*functionPointer_t)(myType1_t*, myType2_t*, myType3_t*); 

setCallback(param1, param2, functionPointer, param4) 

me gustaría usar boost :: bind (si es posible) para pasar en el puntero de función. Preferiría que la función apuntada fuera un miembro de la clase instanciada, no un miembro estático. P.ej.

Class A { 
public: 
    A(); 
protected: 
    int myCallback(myType1_t*, myType2_t*, myType3_t*); //aka functionPointer_t 
} 

¿Se puede hacer esto utilizando boost :: bind and boost :: function? Por How can I pass a class member function as a callback? (la tercera respuesta) parece que podría incluir la siguiente información (en algún lugar, o como un typedef):

boost::function<int (A*, myType1_t*, myType2_t*, myType3*> myCallbackFunction 

Y a continuación, en algún lugar de A (Héctor) llamada boost :: bind de ese tipo, y pasarlo a la convocatoria de la biblioteca C.

¿Esto es posible o estoy fuera de la base? Muchas gracias.

Respuesta

5

No. Los tipos de funtores como boost::function no se convierten en punteros a funciones para su uso con mecanismos de devolución de llamada C.

Sin embargo, la mayoría de los mecanismos de devolución de llamada de C tienen algún tipo de mecanismo de token, por lo que su función de devolución de llamada (que es estática) tiene algún tipo de información de contexto. Usted puede usar esto para escribir una clase contenedora que mapea estas fichas para Functor objetos, y pasa a la ejecución a lo largo de la correcta:

class CallbackManager { 
public: 
    typedef boost::function<int (type1*, type2*, type3*)> callback; 

    static void setCallback(CallbackManager::callback cb) 
    { 
     void *token = ::setCallback(staticCallback); 
     callbacks[token] = callback_I; 
    } 

    static void staticCallback(void* token, type1* a, type2* b, type3* c) 
    { return mcallbacks[token](a, b, c); } 

private: 
    static std::map<void*, callback > callbacks; 
}; 
+0

No puedo cambiar la interfaz de setCallback – jdt141

+0

Lo siento, me perdí esa parte de su publicación. Editado para corregir. –

+0

@ jdt141: ¿Puede abusar de uno de 'param1 , param2, param4' en 'setCallback' para introducir un token que te será devuelto a través de' int (* functionPointer_t) (myType1_t *, myType2_t *, myType3_t *) '? –

0

El problema con las funciones miembro es que reciben automáticamente un puntero a instancia de objeto como el primer parámetro - "este" puntero. Es por eso que no puede usar las funciones miembro funciones de devolución de llamada C. Debe tener el objeto Y el puntero de función juntos para usar una función de miembro.

+0

Eso no tiene sentido. Si eso fuera cierto, no podría degradar una función boost :: a un puntero sin formato por http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer – jdt141

+0

Realmente puede, pero es complicado. Esto: 'A a; a.call(); ' es equivalente a esto: ' A a; A :: call (&a); ' según la especificación de C++, creo. El problema es que un puntero de función sin formato no puede llevar el puntero' this'. –

+0

¡gracias! Eso explica mucho. demasiado centrado en un enfoque y no tomó la ruta obvia. – jdt141

1

no usan mapa, se da por encima de tiempo de ejecución y el desorden de código con mapa estático.

use reinterpret_cast en su lugar.

por ejemplo

// clib.h 
typedef void (*CALLBACK_FUNC)(int code,void *param); 

void set_callback(CALLBACK_FUNC, void * param); 

// a.h 

class A { 
public: 
    A() 
    { 
     ::set_callback(&A::static_callback, this); 
    } 
private: 
    static void static_callback(int code, void * param) 
    { 
     A* self = reinterpret_cast<A*>(param); 
     self->callback(code); 
    } 

    inline void callback(int code) 
    { 
     // write you code here. 
    } 
}; 
Cuestiones relacionadas