2017-04-06 2 views
-1

J'ai un rappel particulier (défini dans certains 'C') qui doit être complété avec du travail supplémentaire qui ne fait pas partie de la fonction de rappel. Il va quelque chose comme ça ...std :: lier une fonction normale mais avec un épilogue

typedef void (*callback_func)(int); 
extern int set_callback(callback_func cb); 

Dans mon code C++, je dois SET_VALUE une promesse qui est définie en dehors de la portée du rappel, dans ma classe. Donc, je devrais capturer la variable de membre std :: promise ou bien ce et l'envoyer au rappel, puis le définir une fois que le rappel a été appelé, seulement que le compilateur ne l'aime pas. Je le fais de cette façon,

set_callback([this](int x) { 
    // some code ... 
    prom.set_value(true); 
}); 

est Ci-dessous l'erreur snipped:

error: no matching function for call to 'set_callback' 
     set_callback([this](int var) { 
     ^~~~~~~~~~~~~~~~~~~~~~~~~ 
note: candidate function not viable: no known conversion from '(lambda at xxx ' to 'callback_func' 
      (aka 'void (*)(int)') for 1st argument 

Je me rends compte que, je dois en quelque sorte « lier » la fonction régulière pour rendre la fonction de rappel d'un std :: fonction , mais je ne suis pas sûr de la manière d'accomplir cela - pour ne pas mentionner l'envoyer un paramètre et exécuter l'épilogue. S'il vous plaît suggérer, merci!

Répondre

0

Les lambdas ne peuvent se désintégrer aux pointeurs de fonction que si la liste de capture est vide. En effet, le code

[this](int x) { 
    // some code ... 
    prom.set_value(true); 
} 

est à peu près équivalente à

struct SomeLambdaName { 
    MyCapture self; 

    auto operator()(int x) const { 
     // some code ... 
     self.prom.set_value(true); 
    } 
}; 

D'autre part, les pointeurs de fonction ne sont que: les pointeurs. Un pointeur vers l'adresse de la fonction à appeler.

En C++, une fonction membre:

struct MyClass { 
    int i; 
    int add_x(int x) { return i = i + x; } 
}; 

est à peu près comme dans le code C (dépendant de l'implémentation):

int add_x(MyClass *self, int x) { return self->i = self->i + x; } 

Si le code C peut être modifié pour prendre void * pour contenir des données arbitraires, cela peut être fait:

typedef void (*callback_func)(int, void * data); 
extern int set_callback(callback_func cb); 
set_callback([](int x, void * data) { 
    MyClass &self = *reinterpret_cast<MyClass *>(data); 
    // some code ... 
    self.prom.set_value(true); 
}); 

Sinon, vous devez avoir des objets statiques ou quelque chose de similaire.

+0

Malheureusement, le code C ne peut pas être changé! En réponse à ce que vous avez proposé, vous suggérez de passer le pointeur this comme un vide * et de l'intégrer (il aurait été plus cohérent d'avoir les données void * comme premier paramètre - essentiellement, c'est ce que le ce pointeur est), mais je crois qu'il existe une meilleure approche pour lier la fonction C à une fonction std :: et ensuite suivre avec un épilogue, mais je ne sais pas comment. – chimp45

+0

@ chimp45 Comme je le disais, il est ** impossible ** de lier une fonction C à une fonction 'std :: '. – Justin

+0

@ chimp45 les pointeurs de fonction incluent la définition des conventions d'appel, "C" ou "C++" et les spécificateurs. Pointer à la fonction C++ dans ce qui n'est pas compatible avec C sans utilisation de "C" externe. Aussi, c'est pourquoi ils ne peuvent pas être utilisés comme pointeur C. Deuxièmement, vous ne pouvez pas passer "ceci" à C à moins que la classe ne soit triviale et POD. vous devez créer une fonction externe "C" dans le code C++ qui ferait un bon travail à l'intérieur – Swift