2010-01-04 13 views
7

Sto lavorando alla configurazione di una funzione membro come callback per una libreria C che sto utilizzando. Il C-libreria di imposta callback come questo:Funzione membro della classe come richiamata utilizzando la funzione boost :: bind e boost ::

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

setCallback(param1, param2, functionPointer, param4) 

Vorrei usare boost :: bind (se possibile) per passare il puntatore a funzione. Preferirei che la funzione indicata fosse un membro della classe istanziata, non un membro statico. Per esempio.

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

questo può essere fatto utilizzando boost :: bind e boost :: funzione? Per How can I pass a class member function as a callback? (3 ° risposta) sembra che ho potuto dichiarare la seguente (da qualche parte, o come un typedef):

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

E poi da qualche parte in A (ctor) chiamata boost :: bind su quel tipo, e passalo alla chiamata della C-library.

È possibile, o sono spento? Grazie mille.

risposta

5

No. I tipi di funzionamento come boost::function non vengono convertiti in puntatori di funzione per l'utilizzo con i meccanismi di callback C.

Tuttavia, la maggior parte dei meccanismi di callback C ha una sorta di meccanismo di token, quindi la funzione di callback (che è statica) ha una sorta di informazioni di contesto. È possibile utilizzare questo di scrivere una classe wrapper che associa questi gettoni per funtore oggetti, e passa l'esecuzione lungo di quello giusto:

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

Non riesco a cambiare l'interfaccia di setCallback – jdt141

+0

Spiacente, ho perso quella parte del tuo post. Modificato per correggere. –

+0

@ jdt141: Puoi abusare di uno di 'param1 , param2, param4' in 'setCallback' per intrufolarsi in un token che ti verrà restituito via' int (* functionPointer_t) (myType1_t *, myType2_t *, myType3_t *) '? –

0

Il problema con le funzioni membro è che ricevono automaticamente un puntatore all'istanza dell'oggetto come primo parametro - "questo" puntatore. Ecco perché non è possibile utilizzare le funzioni membro funzioni di callback in C. Per utilizzare una funzione membro, è necessario che l'oggetto AND sia il puntatore della funzione.

+0

Questo non ha senso. Se fosse vero, non sarei in grado di abbassare di livello una funzione boost :: a un puntatore raw per http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer – jdt141

+0

In realtà puoi, ma è complicato. Questo: 'A a; a.call(); ' è equivalente a questo: ' A a; A :: call (&a);) secondo la specifica C++, il problema è che un puntatore a funzione non può portare con sé il puntatore "this'." –

+0

grazie! troppo focalizzato su un approccio e non ho preso la via ovvia – jdt141

1

non usano carta, dà in testa runtime e il codice di ingombrare con mappa statica.

utilizzare reinterpret_cast invece.

per esempio

// 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. 
    } 
}; 
Problemi correlati