我想创建一个window_callback
函数中可以使用的函数对象。应该通过glfwSet[...]Callback()
在window
中找到一个inline static std::unordered_map<GLFWwindow*, window&> windows_by_handles
,然后调用其适当的处理程序。这是我当前的代码:
GLFWwindow* handle
template <typename... Args>
class window_callback
{
typedef void(window::*member_func_t)(Args...);
member_func_t func;
public:
window_callback(member_func_t func_) :
func(func_)
{
}
void operator() (GLFWwindow* HWND, Args... args)
{
try
{
window& wnd = windows_by_handles.at(HWND);
(wnd.*func)(args...); //error E0165
}
catch (const std::out_of_range&)
{
std::cerr << "Detected callback for unknown window\n";
}
}
operator decltype(&(operator()))() { return &operator(); }
};
对象的创建方式如下(在window_callback
类内部):
window
然后,它们与inline static window_callback<int, int> resize_callback{ &on_resize };
inline static window_callback<double, double> mouse_movement_callback{ &on_mouse_moved };
inline static window_callback<double, double> scroll_callback{ &on_scrolled };
这样的函数绑定(在glfwSet[...]Callback()
类构造函数内部):
window
给定的代码无法编译。在Visual Studio 2019(使用C ++ 17)中进行编译时,它会出现以下错误。前两个错误发生在用户定义的转换运算符声明上:
C2059语法错误:'newline'
C2664 glfwSetFramebufferSizeCallback(handle, resize_callback);
glfwSetCursorPosCallback(handle, mouse_movement_callback);
glfwSetScrollCallback(handle, scroll_callback);
:无法将参数2从GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow *,GLFWframebuffersizefun)
转换为window::window_callback<int,int>
GLFWframebuffersizefun
:无法将参数2从GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow *,GLFWcursorposfun)
转换为window::window_callback<double,double>
GLFWcursorposfun
:无法将参数2从GLFWscrollfun glfwSetScrollCallback(GLFWwindow *,GLFWscrollfun)
转换为window::window_callback<double,double>
有问题的部分是从GLFWscrollfun
类型到适当的函数指针类型的转换。为使此代码正常工作应进行哪些更改,或者以相同方式工作的替代解决方案是什么?
答案 0 :(得分:2)
如何使用函数对象作为回调来调用对象中的成员函数(处理程序)?
我可以在glfwSet [...] Callback()函数中使用的。
Glfw不接受成员函数指针作为回调函数,也不接受函数对象。
您只能注册函数指针。函数指针不能指向非静态成员函数。函数对象的函数调用操作符重载也是成员函数。
您需要编写一个非成员函数(或者如果愿意,可以使用静态成员函数)来包装对成员函数(或函数对象)的调用。
示例:
glfwSetWindowUserPointer
但是,大概您需要访问类(或函数对象)的某些特定实例,而不是默认构造的实例。毕竟,如果不是这样,为什么要使用非静态成员函数。为此,您需要某种方式将对该对象的引用传递到回调中。
GLFW记录的方式是:
每个窗口都有一个用户指针,可以使用
glfwGetWindowUserPointer
进行设置,并可以使用C c; glfwSetWindowUserPointer(window, &c); auto window_size_callback = [](GLFWwindow* window, int w, int h) { C* cptr = static_cast<C*>(glfwSetWindowUserPointer(window)); assert(c); cptr->window_size(window, w, h); };
进行查询。此功能可用于您需要的任何目的,并且不会在窗口的整个使用期内被GLFW修改。
如果要在单个对象上调用所有回调,则使用此方法很简单:
-----------------------------------------------------------------
| Article 1 | Article 2 | Article 3 | Article 4 |
Article 0 | |
| Article 5 | Article 6 | Article 7 | Article 8 |
-----------------------------------------------------------------
不幸的是,GLFW API似乎不支持特定于回调的用户数据。如果您需要不同的对象用于不同的回调,则可以使用自己的从回调到对象的映射,但这并不像上面的示例那么简单。
此外,要非常小心,至少在窗口处于活动状态时使该对象保持活动状态,以免在悬空的指针上调用回调。