回调到非静态方法 [英] Callback to non-static method

查看:89
本文介绍了回调到非静态方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑您的基本GLUT程序.它们只是从一个主要方法运行,并且包含诸如`glutMouseFunc(MouseButton)之类的回调,其中MouseButton是方法的名称.

Think of your basic GLUT programs. They simply run from a main method and contain callbacks like `glutMouseFunc(MouseButton) where MouseButton is the name of a method.

我所做的是将主文件封装到一个类中,以便MouseButton不再是静态函数,而是具有实例.但这给了我一个编译错误:

What I have done is I have encapsulated the main file into a class, so that MouseButton is no longer a static function but has an instance. But doing this gives me a compilation error :

错误2错误C3867:'StartHand :: MouseButton':函数调用缺少参数列表;使用'& StartHand :: MouseButton'创建指向成员c:\ users \ angeleyes \ documents \ Visual Studio 2008 \ projects \ capstone ver 4 \ starthand.cpp 388 IK引擎的指针

Error 2 error C3867: 'StartHand::MouseButton': function call missing argument list; use '&StartHand::MouseButton' to create a pointer to member c:\users\angeleyes\documents\visual studio 2008\projects\capstone ver 4\starthand.cpp 388 IK Engine

由于类很大,因此无法提供代码示例.

It is not possible to provide a code sample as the class is quite huge.

我尝试使用this->MouseButton,但这给出了相同的错误.不能给实例函数提供指针以进行回调吗?

I have tried using this->MouseButton but that gives the same error. Can't a pointer to an instance function be given for callback?

推荐答案

如错误消息所述,您必须使用&StartHand::MouseButton语法来获取指向成员函数(ptmf)的指针.这只是该语言的一部分.

As the error message says, you must use &StartHand::MouseButton syntax to get a pointer to a member function (ptmf); this is simply mandated as part of the language.

使用ptmf时,正在调用的函数glutMouseFunc(在这种情况下)还必须期望获得ptmf作为回调,否则将无法使用非静态的MouseButton.相反,一种常见的技术是使回调与用户提供的void*上下文一起使用,该上下文可以是实例指针-但是执行回调的库必须显式允许该参数.确保您与外部库所期望的ABI相匹配(下面的 handle_mouse 函数)也很重要.

When using a ptmf, the function you are calling, glutMouseFunc in this case, must also expect to get a ptmf as a callback, otherwise using your non-static MouseButton won't work. Instead, a common technique is for callbacks to work with a user-supplied void* context, which can be the instance pointer—but the library doing the callbacks must explicitly allow this parameter. It's also important to make sure you match the ABI expected by the external library (the handle_mouse function below).

由于glut 不允许允许用户提供上下文,因此您必须使用另一种机制:将对象与glut的当前窗口相关联.但是,它确实提供了一种获取当前窗口"的方法,并且我已经使用它来将void*与该窗口关联.然后,您只需要创建一个蹦床即可进行类型转换并调用方法.

Since glut doesn't allow user-supplied context, you have to use another mechanism: associate your objects with glut's current window. It does provide a way to get the "current window", however, and I've used this to associate a void* with the window. Then you simply need to create a trampoline to do the type conversion and call the method.

机械:

#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 的一部分进行管理.

Notice that you don't call glutMouseFunc directly anymore; it is managed as part of [un]set_mousefunc.

以防万一:不清楚:我已经重写了这个答案,因此它应该对您有用,从而避免了C/C ++链接问题的争论.它将按原样编译和运行(没有glut),并且应该只对glut进行少量修改即可:注释或取消注释标记为##E##的4行.

Just in case it isn't clear: I've rewritten this answer so it should work for you and so that it avoids the C/C++ linkage issue being debated. It will compile and run as-is (without glut), and it should work with glut with only minor modification: comment or uncomment the 4 lines marked ##E##.

这篇关于回调到非静态方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆