Scrivendo win32 api wrapper con C ++, come passare questo puntatore alla funzione statica

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

  •  03-07-2019
  •  | 
  •  

Domanda

Voglio convertire l'oggetto funzione in funzione.

Ho scritto questo codice, ma non funziona.

#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;
}

e ho ricevuto un messaggio da g ++, dice uso non valido della funzione membro non statica .

Come posso ottenere il puntatore alla funzione membro dell'istanza?

Modifica : il mio problema originale riguarda l'API Win32.

Sono costretto a scrivere un programma Windows con la vecchia API Win32 a scuola. ma non voglio scrivere un'istruzione orribile come alcuni codici di esempio sul testo. Quindi, ho deciso di scrivere wrapper in C ++.

Voglio scrivere la classe della finestra come ...

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
};

e sono disposto a scrivere la mia classe di applicazione derivando questa classe e sovraccaricando alcuni metodi.

Infine, il mio vero problema è come farlo in 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);
 };

In altre parole, devo chiudere il puntatore alla funzione. Non so come farlo, ma non riesco a credere che non sia possibile farlo in C ++.

Modifica : il titolo originale di questa domanda era Come ottenere la funzione puntatore-membro dell'istanza . Ma questo titolo e la mia domanda non hanno detto abbastanza il mio vero problema. Scusate i primi soccorritori, e grazie, grazie per il suggerimento e la risposta molto utile!

È stato utile?

Soluzione

Aggiorna : ci hai detto quello che volevi. Ho trovato questa domanda qui su SO: Il metodo migliore per l'archiviazione questo puntatore per l'uso in WndProc . Non sono un programmatore di Windows, ma il ragazzo di Adam Rosenfield sembra aver ragione nell'usare SetWindowLongPtr e GetWindowLongPtr. Quindi, lo usi in questo modo:

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.
}

Registra quella funzione come wnd-proc e archivia il puntatore this del tuo oggetto Window usando SetWindowLongPtr. Nella struttura WNDCLASSEX , esiste un campo cbWndExtra a cui si assegna sizeof (Window *) , che è spazio sufficiente per contenere solo questo puntatore. Quindi puoi chiamare

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

per mettere questo puntatore in quella regione. Quindi riceverlo come sopra e delegare la funzione membro reale. In teoria si potrebbe anche usare una funzione membro statica. Ma devi stare attento. La chiamata di una funzione membro statica dal codice C può causare errori, poiché la convenzione di chiamata potrebbe essere diversa tra il codice C e il codice C ++. Per Windows, potrebbe non essere un problema - non lo so. Quindi, controlla anche te stesso.


La cosa che provi non è valida. Si tenta di restituire un puntatore all'operatore di chiamata della funzione, ma non viene fornito alcun oggetto quando viene effettuata la chiamata, oltre al fatto che l'operatore di conversione ha il tipo sbagliato. Il tipo restituito dall'operatore di conversione ha il tipo di puntatore a funzione, ma non il tipo di puntatore a funzione membro. Il più vicino a cui puoi arrivare è usare il tipo giusto:

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();
    }
};

Ora, il tuo operatore di conversione non è nemmeno considerato, perché deve essere chiamato in questo modo:

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

E manualmente in questo modo:

// 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 solita sintassi della chiamata di funzione non riesce a risolverlo. In breve, ciò che provi non è possibile.

Penso che un'altra domanda sia: perché diamine vuoi farlo? Penso che possiamo aiutarti meglio quando sappiamo qual è il problema originale. Se stai cercando di farlo apparire e funzionare come una chiamata di funzione, non hai bisogno di alcun operatore di conversione:

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

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

Altri suggerimenti

I puntatori del metodo di istanza sono un po 'complicati e sono animali completamente diversi rispetto ai puntatori di funzione "normali".

Scopri cosa C ++ FAQ lite section 33 ha da dire al riguardo. Vedi anche this e questo per esempi concreti.

Un puntatore a una funzione di membro non statico è diverso da un puntatore a una funzione statica (o a una funzione globale e quindi statica) perché i membri non statici hanno il "presente" nascosto. parametro.

Il tipo di globali o statici è qualcosa come int (*) (int)

Tuttavia, il tipo di nonstatic è simile a int (ClassName :: *) (int).

Detto questo, il tuo codice contiene elementi più strani, poiché sembra che tu stia cercando di assegnare il costruttore o un oggetto costruito nel puntatore della funzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top