При написании Win32 API-оболочки с C ++, как передать этот указатель на статическую функцию - PullRequest
1 голос
/ 05 января 2009

Я хочу преобразовать объект функции в функцию.

Я написал этот код, но он не работает.

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

и я получил сообщение от g ++, говорит invalid use of non-static member function.

Как получить указатель на функцию-член экземпляра?

Редактировать : Моя первоначальная проблема связана с Win32 API.

В школе меня заставляют писать программы для Windows со старым Win32 API. но я не хочу писать ужасные операторы switch, как некоторые примеры кода в тексте. Затем я решил написать оболочку на C ++.

Я хочу написать класс окна как ...

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

и я готов написать свой класс приложения с выводом этого класса и перегрузкой некоторых методов.

Наконец, мой настоящий пробрем - как это сделать в 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);
 };

Другими словами, я должен сделать замыкание на указатель на функцию. Я не знаю, как это сделать, но я не могу поверить, что это не может сделать в C ++.

Редактировать : Оригинальный заголовок этого вопроса был Как получить указатель на функцию-член экземпляра . Но этот заголовок и мой вопрос не рассказали о моей реальной проблеме. Извините за ранние ответы, и litb, спасибо за предложение и очень полезный ответ!

Ответы [ 3 ]

4 голосов
/ 05 января 2009

Обновление : Вы сказали нам, что вы хотите. Я нашел этот вопрос здесь на SO: Лучший метод для хранения этого указателя для использования в WndProc . Я не программист Windows, но парень Адам Розенфилд, кажется, прав в использовании SetWindowLongPtr и GetWindowLongPtr. Итак, вы используете это так:

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

Зарегистрируйте эту функцию как wnd-proc и сохраните указатель this вашего объекта Window, используя SetWindowLongPtr. В структуре WNDCLASSEX есть поле cbWndExtra, которому вы назначаете sizeof(Window*), что достаточно для хранения указателя this. Тогда вы можете позвонить

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

чтобы поместить указатель this в этот регион. Затем получите его, как указано выше, и передайте реальную функцию-член. Теоретически вы также можете использовать статическую функцию-член. Но вы должны быть осторожны. Вызов статической функции-члена из кода C может привести к ошибкам, потому что соглашение о вызовах может отличаться для кода C и кода C ++. Для Windows это может не быть проблемой - я не знаю. Так что лучше проверь себя дополнительно.


То, что вы пытаетесь, недопустимо. Вы пытаетесь вернуть указатель на оператор вызова функции, но при вызове объект не предоставляется, кроме того, что ваш оператор преобразования имеет неправильный тип. Тип, который возвращает оператор преобразования, имеет тип указателя на функцию, но не тип указателя на функцию-член. Самое близкое, что вы можете получить, это использовать правильный тип:

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

Теперь ваш оператор преобразования даже не рассматривается, потому что он должен называться так:

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

И вручную вот так:

// 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

Обычный синтаксис вызова функции не справляется с этим. Короче, то, что вы пытаетесь, невозможно.

Я думаю, что другой вопрос, почему, черт возьми, ты хочешь это сделать? Я думаю, что мы можем помочь вам лучше, когда узнаем, в чем заключается изначальная проблема Если вы пытаетесь заставить его выглядеть и работать как вызов функции, вам вообще не нужны операторы преобразования:

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

adder a(10); cout << a(2); // expected: 12
1 голос
/ 05 января 2009

Указатели на метод экземпляра немного хитры и совершенно разные звери по сравнению с «нормальными» указателями на функции.

Посмотрите, что об этом говорится в разделе FAQ по *1003*. Также см. это и это для конкретных примеров.

0 голосов
/ 05 января 2009

Указатель на нестатическую функцию-член отличается от указателя на статическую функцию (или на глобальную и, следовательно, статическую функцию), поскольку нестатические члены имеют скрытый параметр "this".

Тип для глобалов или статик - это что-то вроде int (*) (int)

Однако тип для нестатического типа - это что-то вроде int (ClassName :: *) (int).

При этом в вашем коде есть более странные вещи, так как вы, кажется, пытаетесь назначить конструктор или созданный объект в указатель на вашу функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...