使用std::bind将类成员函数注册为函数的回调
Registering a class member function as a callback to a function using std::bind
我试图注册一个类成员函数作为(常规)回调函数。除非我误解了什么,否则使用std::bind(使用c++ 11)应该可以实现这一点。我这样做:
std::function<void (GLFWwindow*, unsigned int)> cb = std::bind(&InputManager::charInputCallback, this, std::placeholders::_1, std::placeholders::_2);
我的回调函数定义如下:
void InputManager::charInputCallback(GLFWwindow* window, unsigned int key)
我能够在使用随机数据创建后立即测试cb
:
cb(NULL, 0x62);
我可以确认这个数据被正确地发送到回调函数,从它打印到终端。
然而,我想将这个函数注册到GLFW,以便程序窗口的按键被发送到回调函数。我这样做:
glfwSetCharCallback(window, (GLFWcharfun) &cb);
就像我之前说的:手动调用它很好。当我注册它作为回调虽然,我得到一个分割错误,每当我按下一个键和GLFW试图调用回调函数。
std::bind不是我要找的吗?我用错了吗?
编辑:我不认为这个问题是重复的,我怎么能传递一个类成员函数作为回调?就像它被鉴定为。虽然我们正在处理相同的问题,但我要问的是使用std::bind的特殊解决方案,在另一个问题的一个答案中只提到了它,但从未解释过它。
函数声明如下:
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
)
其中GLFWcharfun定义为typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int)
这里有一个明显的问题,你没有机会传递一个'context'对象,它会自动将回调映射回InputManager的实例。因此,您必须使用惟一可用的键——窗口指针,手动执行映射。
这是一个策略…
#include <map>
#include <mutex>
struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
);
struct InputManager;
struct WindowToInputManager
{
struct impl
{
void associate(GLFWwindow* window, InputManager* manager)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_[window] = manager;
}
void disassociate(GLFWwindow* window, InputManager* manager)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_.erase(window);
}
InputManager* find(GLFWwindow* window) const
{
auto lock = std::unique_lock<std::mutex>(mutex_);
auto i = mapping_.find(window);
if (i == mapping_.end())
return nullptr;
else
return i->second;
}
mutable std::mutex mutex_;
std::map<GLFWwindow*, InputManager*> mapping_;
};
static impl& get_impl() {
static impl i {};
return i;
}
void associate(GLFWwindow* window, InputManager* manager)
{
get_impl().associate(window, manager);
}
void disassociate(GLFWwindow* window, InputManager* manager)
{
get_impl().disassociate(window, manager);
}
InputManager* find(GLFWwindow* window)
{
return get_impl().find(window);
}
};
struct InputManager
{
void init()
{
// how to set up the callback?
// first, associate the window with this input manager
callback_mapper_.associate(window_, this);
// now use a proxy as the callback
glfwSetCharCallback(window_, &InputManager::handleCharCallback);
}
static void handleCharCallback(GLFWwindow * window,
unsigned int ch)
{
// proxy locates the handler
if(auto self = callback_mapper_.find(window))
{
self->charInputCallback(window, ch);
}
}
void charInputCallback(GLFWwindow * window,
int ch)
{
// do something here
}
GLFWwindow* window_;
static WindowToInputManager callback_mapper_;
};
或者如果你喜欢闭包:
#include <map>
#include <mutex>
struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
);
struct InputManager;
struct WindowToInputManager
{
using sig_type = void (GLFWwindow *, unsigned int);
using func_type = std::function<sig_type>;
struct impl
{
void associate(GLFWwindow* window, func_type func)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_[window] = std::move(func);
}
void disassociate(GLFWwindow* window)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_.erase(window);
}
const func_type* find(GLFWwindow* window) const
{
auto lock = std::unique_lock<std::mutex>(mutex_);
auto i = mapping_.find(window);
if (i == mapping_.end())
return nullptr;
else
return std::addressof(i->second);
}
mutable std::mutex mutex_;
std::map<GLFWwindow*, func_type> mapping_;
};
static impl& get_impl() {
static impl i {};
return i;
}
template<class F>
void associate(GLFWwindow* window, F&& f)
{
get_impl().associate(window, std::forward<F>(f));
glfwSetCharCallback(window, &WindowToInputManager::handleCharCallback);
}
void disassociate(GLFWwindow* window)
{
// call whatever is the reverse of glfwSetCharCallback here
//
// then remove from the map
get_impl().disassociate(window);
}
const func_type* find(GLFWwindow* window)
{
return get_impl().find(window);
}
static void handleCharCallback(GLFWwindow* w, unsigned int ch)
{
auto f = get_impl().find(w);
// note - possible race here if handler calls disasociate. better to return a copy of the function?
if (f) {
(*f)(w, ch);
}
}
};
struct InputManager
{
void init()
{
callback_mapper_.associate(window_, [this](auto* window, int ch) { this->charInputCallback(window, ch); });
}
void charInputCallback(GLFWwindow * window,
int ch)
{
// do something here
}
GLFWwindow* window_;
WindowToInputManager callback_mapper_;
};
相关文章:
- 构造函数的链接时间自动注册
- 如何将不同的成员函数指针分配给注册类的不同实例?
- 即使在已注册的 C 函数中,lua_sethook也会触发吗?
- 如何最大限度地减少使用标量 SIMD 内部函数的 SIMD 注册表的双重负载开销
- 当调用了一个用atexit()注册的函数时
- Openssl 线程安全回调函数注册,包括直接调用和间接调用
- 具有 VS2012 NativeDEStepOver 注册表项,该注册表项阻止单步执行特定函数的格式更改
- 为什么这行不通?第二个函数无法注册?
- 覆盖OnFileOpen和OnFileSave函数-注册表未更新
- 注册用于提升io_service的每个对象的回调函数是什么?
- 如何使用 atexit() 注册一个非 void 函数
- 注册一个C++类,以便函数稍后可以循环访问所有已注册的类
- Cython:在DLL中注册用于回调的Python函数
- 如何将类构造函数注册C++ Lua 用户数据并默认使用它
- 如何从无法注册到函数向导的 xll 加载项调用函数
- 为什么 COM 类需要构造函数?如何在不注册的情况下使用 COM 类
- 在 LuaBridge 中注册一个类的函数,然后通过 lua 脚本调用它?
- 如何在c++中不绑定lua的情况下将成员函数注册到lua
- 使用std::bind将类成员函数注册为函数的回调
- 如何确定dll是否已使用我的c++函数注册