C++ à l'Aide de la Méthode de Classe comme un Pointeur de Fonction Type
Dans un C lib, il y a une fonction attend un pointeur de fonction telles que:
lasvm_kcache_t* lasvm_kcache_create(lasvm_kernel_t kernelfunc, void *closure)
où lasvm_kernel_t est défini comme:
typedef double (*lasvm_kernel_t)(int i, int j, void* closure);
Maintenant, si j'envoie une méthode définie dans une classe à lasvm_kcache_create:
double cls_lasvm::kernel(int i, int j, void *kparam)
...
lasvm_kcache_t *kcache=lasvm_kcache_create(&kernel, NULL);
Je reçois: "impossible de convertir de ‘double (cls_lasvm::)(int, int, void)’ à ‘double ()(int, int, void)’"
Que dois-je faire?
OriginalL'auteur paul simmons | 2009-11-15
Vous devez vous connecter pour publier un commentaire.
Je suis en supposant que le
closure
argument est un contexte de "témoin" pour l'utilisation de la fonction de rappel pour obtenir contexte approprié. C'est un acomon idiome pour les fonctions de rappel, et semble être ce qui se passe fondée sur les extraits de code que vous avez fournies (mais je ne sais pas pour vous, car je ne sais rien à propos dekcache_create()
à l'exception de ce que vous avez posté ici).Vous pouvez utiliser le cookie de passer un pointeur vers la
cls_lasvm
exemple, vous traitez de la sorte:Si je me trompe au sujet de dispositif de fermeture d'un contexte cookie, puis votre fonction de rappel dans le
cls_lasvm
les besoins de la classe à être statique:Noter qu'un C fonction de rappel implémenté en C++ doit être
extern "C"
. Il peut sembler à travailler comme une fonction statique dans une classe parce que la classe des fonctions statiques utilisent souvent la même convention d'appel C de la fonction. Cependant, en faisant cela est un bug en attente de se produire (voir les commentaires ci-dessous), merci donc de ne pas passer par unextern "C"
wrapper à la place.Si
closure
n'est pas un contexte de biscuit et pour quelque raisoncls_lasvm::kernel()
ne peut pas être statique, alors vous devez trouver un moyen de ranger unthis
pointeur de quelque part et de récupérer le pointeur dans lalasvm_kcache_create_callback()
fonction, semblable à la façon dont je l'ai fait dans mon premier exemple, sauf que le pointeur est à venir cdès certains mécanisme de vous imaginer vous-même. Notez que cela fera probablement l'aide delasvm_kcache_create()
non réentrant et non thread-safe. Qui peut ou peut ne pas être un problème en fonction de vos circonstances particulières.OK je vais supprimer la suggestion qu'il est susceptible d'être en sécurité. Homme - là est un beaucoup de code qui va se briser si/lorsque ces optimisations (ou autre) devenu monnaie courante. Je suppose que plus de 75% du temps je vois C rappels être utilisé dans du code C++, il est fait directement par l'intermédiaire d'une fonction membre statique.
Je le vois a chaque maintenant et puis, les jeunes codeurs. Mais dans les grandes companyies ces erreurs toujours obtenir la toux à l'examen du code (et une fois que la toux, l'erreur n'est pas nouveau comme nous pouvons le faire très embarrassant). Donc, je l'ai vu (pas beaucoup) dans les projets open source ont été sages têtes les têtes ne sont pas dénigrement de la jeune génération.
Je devine que vous n'avez pas à traiter avec beaucoup de code de Windows (tout comme je ne vois pas beaucoup de code Unix) - je le vois tout le temps là-bas. Je serai très surpris si MSVC jamais de pauses à l'aide de fonctions membres statiques que C rappels.
OriginalL'auteur Michael Burr
Chaque membre C++ la fonction implicite, cachée, le premier paramètre,
this
.Donc la méthode
double cls_lasvm::kernel(int i, int j, void* kparam)
est vraiment:double cls_lasvm::kernel(cls_lasvm* this, int i, int j, void* kparam)
, et il est inapproprié/impossible de l'utiliser comme une fonction de pointeur de paramètre.À faire des progrès, de convertir votre méthode statique-membre-de la méthode. Qui permet de supprimer le
this
pointeur. Vous pouvez avoir encore d'autres problèmes à surmonter, mais c'est un bon début.this
est disponible dans le destinataire de l'appel, c'est tout. Donc il n'est pas "vraiment" que chose que vous avez dit - essayez de changerkernelfunc
à ce type, et le code ne compile pas. pointeur de fonction et pointeur-à-membres de la fonction sont des choses différentes.Je pense que c'est habituellement défini comme le premier paramètre, en fait. Cette distinction ne faire une différence, puisque d'autres fonctions (et d'autres langues, je suppose) ont besoin de savoir dans quel ordre il faut les passer ces paramètres.
Ne pas l'utilisation de membre statique méthode pour C les méthodes de rappel. Il n'est pas garanti que le C++ standard choisi délibérément de ne pas spécifier de l'ABI.
accordé, l'explication n'est pas précis à 100%, mais c'est une bonne simplification et correspond à (presque?) chaque véritable mise en œuvre de la fonction de membre de signatures.
Je suis d'accord avec Steve. C'est une trop grande simplification; il fait allusion à une équivalence qui n'est pas vraiment là dans la pratique. Visual C++ (32-bit), qui essentiellement utilise la pile pour la transmission de paramètres, utilise un registre pour le
this
pointeur pour les non-fonctions membres statiques. Cela signifie qu'il n'est pas un paramètre supplémentaire, soit au début ou la ou la fin de la liste des paramètres, c'est juste un paramètre supplémentaire. Cela signifie également qu'il n'y a aucun moyen de le jeter aux statique ou non-membre de la fonction et de pouvoir l'appeler correctement.OriginalL'auteur abelenky
Si c'est une bibliothèque C, dont le code vous ne pouvez pas modifier, puis il n'y a pas beaucoup que vous pouvez faire à ce sujet. Vous ne serez pas en mesure d'appeler la fonction membre comme ils ont besoin de
this
pointeur fonctionne correctement (pour obtenir les attributs de l'objet). La solution plus simple, je pense, à l'aide de tiersvoid*
param passer autourthis
pointeur. Vous pouvez définir struct comme après la définition d'un plus typedef comme:Je n'ai pas compilé, j'espère qu'il fait sens.
Puis dans votre classe de définir une méthode statique qui reçoit l'appel de la bibliothèque:
Lors d'un appel, vous devriez utiliser quelque chose comme:
OriginalL'auteur Ponting