2010-01-04 8 views
7

Je travaille sur la configuration d'une fonction membre en tant que rappel d'une bibliothèque C que j'utilise. La bibliothèque C met en place callbacks comme ceci:Fonction de membre de classe comme rappel utilisant boost :: bind et boost :: function

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

setCallback(param1, param2, functionPointer, param4) 

Je voudrais utiliser boost :: bind (si possible) pour passer le pointeur de fonction. Je préférerais que la fonction pointée sur soit un membre de la classe instanciée, pas un membre statique. Par exemple.

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

Cela peut-il être fait en utilisant boost :: bind et boost :: function? Par How can I pass a class member function as a callback? (la 3e réponse), il semble que je pourrais déclarer les éléments suivants (quelque part, ou comme typedef):

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

Et puis quelque part dans A (cteur) boost d'appel :: bind sur ce type, et passez-le dans l'appel C-library. Est-ce possible ou suis-je hors de la base? Merci beaucoup.

Répondre

5

No. types de foncteurs comme boost::function ne se convertissent pas des pointeurs de fonction pour une utilisation avec des mécanismes de rappel C.

Cependant, la plupart des mécanismes de rappel C ont une sorte de mécanisme de jeton, de sorte que votre fonction de rappel (qui est statique) a une sorte d'informations de contexte. Vous pouvez l'utiliser pour écrire une classe wrapper qui associe ces jetons pour Functor objets, et passe l'exécution le long de la droite:

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

je ne peux pas changer l'interface de setCallback – jdt141

+0

Désolé, j'ai raté cette partie de votre message modifié pour corriger –

+0

@ jdt141:.. Pouvez-vous abuser de l'un des 'param1 , param2, param4' dans 'setCallback' de se faufiler un jeton qui sera retourné à vous via' int (* functionPointer_t) (myType1_t *, myType2_t *, myType3_t *) ' –

0

Le problème avec les fonctions membres est qu'elles reçoivent automatiquement un pointeur vers l'instance de l'objet en tant que premier paramètre - "this" pointeur. C'est pourquoi vous ne pouvez pas utiliser les fonctions membres d'une fonction de rappel C. Vous devez avoir l'objet ET le pointeur de fonction ensemble pour utiliser une fonction membre.

+0

Cela n'a pas de sens. Si cela était vrai, je ne serais pas en mesure de rétrograder un boost :: fonction à un pointeur brut par http://stackoverflow.com/questions/282372/demote-boostfunction-to-a-plain-function-pointer – jdt141

+0

Vous pouvez réellement, mais c'est compliqué. Ceci: 'A a; a.call(); ' est équivalente à celle-ci: ' A a; A :: call (&a); ' selon la spécification C++, je crois.) Le problème est qu'un pointeur de fonction brute ne peut pas emmener le pointeur' this' avec lui –

+0

merci, ça explique beaucoup. . trop concentré sur une approche et n'a pas pris la route évidente – jdt141

1

ne pas utiliser la carte, il donne les frais généraux d'exécution et encombrer le code sur la carte statique.

utilisez reinterpret_cast à la place.

par exemple

// 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. 
    } 
}; 
Questions connexes