Как говорится в сообщении об ошибке, вы должны использовать синтаксис &StartHand::MouseButton
, чтобы получить указатель на функцию-член (ptmf); это просто как часть языка.
При использовании ptmf функция, которую вы вызываете, в данном случае glutMouseFunc, также должна ожидать получения ptmf в качестве обратного вызова, в противном случае использование нестатической MouseButton не будет работать. Вместо этого общепринятым методом для обратных вызовов является работа с предоставленным пользователем контекстом void*
, который может быть указателем экземпляра - но библиотека, выполняющая обратные вызовы, должна явно разрешить этот параметр. Также важно убедиться, что вы соответствуете ABI, ожидаемому от внешней библиотеки (функция handle_mouse ниже).
Так как glut не разрешает пользовательский контекст, вы должны использовать другой механизм: связать ваши объекты с текущим окном glut. Тем не менее, он предоставляет способ получить «текущее окно», и я использовал его, чтобы связать void*
с окном. Затем вам просто нужно создать батут , чтобы выполнить преобразование типов и вызвать метод.
Машина:
#include <map>
int glutGetWindow() { return 0; } // make this example compile and run ##E##
typedef std::pair<void*, void (*)(void*,int,int,int,int)> MouseCallback;
typedef std::map<int, MouseCallback> MouseCallbacks;
MouseCallbacks mouse_callbacks;
extern "C" void handle_mouse(int button, int state, int x, int y) {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) { // should always be true, but possibly not
// if deregistering and events arrive
i->second.second(i->second.first, button, state, x, y);
}
}
void set_mousefunc(
MouseCallback::first_type obj,
MouseCallback::second_type f
) {
assert(obj); // preconditions
assert(f);
mouse_callbacks[glutGetWindow()] = MouseCallback(obj, f);
//glutMouseFunc(handle_mouse); // uncomment in non-example ##E##
handle_mouse(0, 0, 0, 0); // pretend it's triggered immediately ##E##
}
void unset_mousefunc() {
MouseCallbacks::iterator i = mouse_callbacks.find(glutGetWindow());
if (i != mouse_callbacks.end()) {
mouse_callbacks.erase(i);
//glutMouseFunc(0); // uncomment in non-example ##E##
}
}
Пример:
#include <iostream>
struct Example {
void MouseButton(int button, int state, int x, int y) {
std::cout << "callback\n";
}
static void MouseButtonCallback(
void* self, int button, int state, int x, int y
) {
static_cast<Example*>(self)->MouseButton(button, state, x, y);
}
};
int main() {
Example obj;
set_mousefunc(&obj, &Example::MouseButtonCallback);
return 0;
}
Обратите внимание, что вы больше не вызываете glutMouseFunc напрямую; он управляется как часть [un] set_mousefunc .
На всякий случай, если неясно: я переписал этот ответ, чтобы он работал для вас и чтобы избежать обсуждения вопроса о связях C / C ++. Он будет компилироваться и запускаться как есть (без переизбытка), и он должен работать с переизбытком с незначительными изменениями: прокомментировать или раскомментировать 4 строки, помеченные ##E##
.