Al escribir Win32 api wrapper con C ++, cómo pasar este puntero a la función estática

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

  •  03-07-2019
  •  | 
  •  

Pregunta

Quiero convertir el objeto de función en función.

Escribí este código, pero no funciona.

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

y recibí un mensaje de g ++, dice uso no válido de la función miembro no estática .

¿Cómo obtengo el puntero a la función miembro de la instancia?

Editar : mi problema original tiene que ver con la API de Win32.

Estoy obligado a escribir un programa de Windows con el viejo API de Win32 en la escuela. pero no quiero escribir una declaración de cambio horrible como algunos códigos de ejemplo en el texto. Entonces, decidí escribir wrapper en C ++.

Quiero escribir la clase de ventana como ...

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

y estoy dispuesto a escribir mi clase de aplicación derivando esta clase y sobrecargando algunos métodos.

Finalmente, mi problema real es cómo hacer esto 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 otras palabras, tengo que hacer el cierre en el puntero de función. No sé cómo hacer esto, pero no puedo creer que esto no pueda hacerse en C ++.

Editar : el título original de esta pregunta era Cómo obtener la función de puntero a miembro de la instancia . Pero este título y mi pregunta no explicaron lo suficiente mi problema real. Disculpe a los primeros que respondieron, y litb, ¡gracias por la sugerencia y la respuesta muy útil!

¿Fue útil?

Solución

Actualización : nos dijiste lo que querías. Encontré esta pregunta aquí en SO: El mejor método para almacenar este puntero para su uso en WndProc . No soy un programador de Windows, pero el chico de Adam Rosenfield parece tener razón al usar SetWindowLongPtr y GetWindowLongPtr. Entonces, lo usas así:

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

Registre esa función como wnd-proc y almacene el puntero this de su objeto Window usando SetWindowLongPtr. En la estructura WNDCLASSEX , hay un campo cbWndExtra al que asigna sizeof (Window *) , que es suficiente espacio de almacenamiento para contener simplemente este puntero. Entonces puedes llamar

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

para poner el puntero de este en esa región. Luego, recíbalo como el anterior y delegue en la función miembro real. En teoría, también podría utilizar una función miembro estática. Pero tienes que tener cuidado. Llamar a una función miembro estática desde el código C puede causar errores, porque la convención de llamada puede ser diferente entre el código C y el código C ++. Para Windows, eso puede no ser un problema, no lo sé. Así que mejor compruebe usted mismo además.


Lo que intentas no es válido. Intenta devolver un puntero al operador de llamada de función, pero no se proporciona ningún objeto cuando se realiza la llamada, además de que su operador de conversión tiene el tipo incorrecto. El tipo que devuelve el operador de conversión tiene un tipo de puntero a función, pero no un tipo de puntero a función miembro. Lo más cerca que puede llegar es usar el tipo adecuado:

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

Ahora, su operador de conversión ni siquiera se considera, porque tiene que llamarse así:

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

Y manualmente de esta manera:

// 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 sintaxis de llamada de función habitual no se ocupa de eso. En resumen, lo que intentas no es posible.

Creo que otra pregunta es, ¿por qué diablos quieres hacer eso? Creo que podemos ayudarlo mejor cuando sepamos cuál es el problema original. Si está tratando de hacer que se vea y funcione como una llamada a una función, no necesita ningún operador de conversión:

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

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

Otros consejos

Los punteros del método de instancia son un poco complicados y son bestias completamente diferentes en comparación con los punteros de función "normales".

Vea lo que C ++ FAQ lite sección 33 Tiene que decir al respecto. También vea this y this para ejemplos concretos.

Un puntero a una función miembro no estática es diferente de un puntero a una función estática (o a una función global y, por lo tanto, estática) porque los miembros no estáticos tienen el " este " oculto; parámetro.

El tipo para globals o statics es algo como int (*) (int)

Sin embargo, el tipo para no estático es algo como int (ClassName :: *) (int).

Dicho esto, su código tiene cosas más extrañas, ya que parece que está intentando asignar el constructor o un objeto construido a su puntero de función.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top