En écrivant win32 api wrapper avec C ++, comment passer ce pointeur à une fonction statique

StackOverflow https://stackoverflow.com/questions/412183

  •  03-07-2019
  •  | 
  •  

Question

Je veux convertir un objet fonction en fonction.

J'ai écrit ce code, mais cela ne fonctionne pas.

#include <iostream>

typedef int (*int_to_int)(int);

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
    operator int_to_int () {
        return this->*&adder::operator();
    }
};

int main(void) {
    adder add_two(2);
    int_to_int add_fn = add_two;
    std::cout << add_two(3) << std::endl; // expect 5
    std::cout << add_fn(3)  << std::endl; // expect 5
    add_fn = adder(5);
    std::cout << add_fn(3)  << std::endl; // expect 8
    return 0;
}

et j'ai reçu un message de g ++, dit utilisation non valide de la fonction membre non statique .

Comment puis-je obtenir un pointeur sur la fonction membre de l'instance?

Modifier : mon problème initial concerne l'API Win32.

Je suis obligé d'écrire un programme Windows avec l'ancienne API Win32 à l'école. mais je ne veux pas écrire d'horrible instruction switch comme certains exemples de codes sur du texte. Ensuite, j'ai décidé d'écrire wrapper en C ++.

Je veux écrire la classe window comme ...

class Window {
public:
    LRESULT update (HWND, UINT, WPARAM, LPARAM);
    void run();
    // below methods are called by update()
    virtual void onclick(int, int);
    virtual void ondraw(); // ... and more methods
};

et je souhaite écrire ma classe d'application en dérivant cette classe et en surchargeant certaines méthodes.

Enfin, mon problème actuel est comment procéder en C ++.

 // on initializing my window object,
 // I must register window class with callback which is 
 // not a C++ function object.
 // I try to explain what I want to do with psudocode mixing C++ and javascript.
 WNDCLASS wndclass;
 Window *self = this;
 wndclass.lpfnWndProc = function () {
     return self.update.apply(self, argunemts);
 };

En d’autres termes, je dois transformer la fermeture en pointeur de fonction. Je ne sais pas comment faire cela, mais je ne peux pas croire que cela ne puisse pas être fait en C ++.

Modifier : le titre d'origine de cette question était Comment obtenir le pointeur sur la fonction membre de l'instance . Mais ce titre et ma question ne disaient pas assez mon vrai problème. Désolé pour les premiers intervenants, et merci, merci pour votre suggestion et votre réponse très utile!

Était-ce utile?

La solution

Mise à jour : vous nous avez dit ce que vous souhaitiez. J'ai trouvé cette question ici sur SO: meilleure méthode de stockage ce pointeur à utiliser dans WndProc . Je ne suis pas un programmeur Windows, mais le gars d'Adam Rosenfield semble avoir raison d'utiliser SetWindowLongPtr et GetWindowLongPtr. Donc, vous l'utilisez comme ceci:

LRESULT CALLBACK my_callback(HWND hwnd, UINT ui, WPARAM wp, LPARAM lp) {
    Window * self = reinterpret_cast<Window*>(
        GetWindowLongPtr(hwnd, 0));
    return self->update(hwnd, ui, wp, lp); // handle it.
}

Enregistrez cette fonction en tant que wnd-proc et stockez le pointeur this de votre objet Window à l'aide de SetWindowLongPtr. Dans la structure WNDCLASSEX , il existe un champ cbWndExtra auquel vous affectez sizeof (Window *) , qui est une mémoire suffisante pour contenir aiguille. Ensuite, vous pouvez appeler

SetWindowLongPtr(my_hwnd, 0, reinterpret_cast<LONG_PTR>(this));

pour placer le pointeur this dans cette région. Ensuite, recevez-le comme ci-dessus et déléguez-le à la fonction de membre réel. Vous pouvez théoriquement aussi utiliser une fonction membre statique. Mais il faut faire attention. L'appel d'une fonction membre statique à partir de code C peut être à l'origine de bogues, car la convention d'appel peut être différente entre le code C et le code C ++. Pour Windows, cela peut ne pas être un problème - je ne sais pas. Alors mieux vaut vérifier vous-même en plus.

La chose que vous essayez n'est pas valide. Vous essayez de renvoyer un pointeur à l'opérateur d'appel de fonction, mais aucun objet n'est fourni lors de l'appel. En outre, votre opérateur de conversion a un type incorrect. Le type renvoyé par l'opérateur de conversion a le type de pointeur de fonction, mais pas le type de pointeur de fonction membre. Le plus proche que vous pouvez obtenir est d'utiliser le type approprié:

struct adder;
typedef int (adder::*int_to_int)(int);

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
    operator int_to_int () {
        return &adder::operator();
    }
};

Maintenant, votre opérateur de conversion n'est même pas pris en compte, car il doit s'appeler ainsi:

adder a(10); cout << (a.*(int_to_int)a)(2); // expected: 12

Et manuellement comme ceci:

// note, we just get the member function pointer using the conversion operator.
// Nothing is related to the actual temporary adder object. 
int_to_int i = adder(5);
cout << (adder(10).*i)(2); // expected: 12

La syntaxe habituelle d'appel de fonction ne résout pas le problème. En bref, ce que vous essayez n'est pas possible.

Je pense qu’une autre question est la suivante: pourquoi diable voulez-vous faire cela? Je pense que nous pouvons mieux vous aider lorsque nous savons quel est le problème initial. Si vous essayez de faire en sorte que cela ressemble à un appel de fonction, vous n'avez pas du tout besoin d'opérateurs de conversion:

struct adder {
    int n_;
    adder (int n) : n_(n) {}
    int operator() (int x) { return x + n_; }
};

adder a(10); cout << a(2); // expected: 12

Autres conseils

Les pointeurs de méthode d’instance sont un peu délicats et sont complètement différents des bêtes par rapport aux pointeurs de fonction "normaux".

Voir ce que la FAQ C ++ lite section 33 a à dire à ce sujet. Voir aussi this et this pour des exemples concrets.

Un pointeur sur une fonction membre non statique est différent d'un pointeur sur une fonction statique (ou sur une fonction globale et donc statique) car les membres non statiques ont le caractère caché "this". paramètre.

Le type pour les globales ou la statique est quelque chose comme int (*) (int)

Cependant, le type de nonstatic est quelque chose comme int (ClassName :: *) (int).

Cela étant dit, votre code contient des choses plus étranges, car vous semblez vouloir assigner le constructeur ou un objet construit à votre pointeur de fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top