我正在使用 glfw 来设置 OpenGL 可视化。我想将回调函数设置为非静态函数来访问类变量。但是,当我执行以下操作时,出现错误“必须调用对非静态成员函数的引用”。我知道在这种情况下回调函数必须是静态的,但有没有办法实现目标?
class Viewer
{
public:
Viewer()
{
glfwSetErrorCallback(errorCallback);
}
private:
void errorCallback(int error, const char* description)
{
// print more class variables
std::cerr << "Error: " << description << std::endl;
}
};
GLFW 是C 接口,不支持C++ 对象。对于窗口、监视器和操纵杆回调函数,您可以为这些对象中的每一个存储一个用户指针,在回调函数中检索它,并使用它来调用对象的成员函数(方法)。
错误回调是不可能的。相反,您可以使用全局变量来存储指向本地错误处理程序的指针。如果此变量不是
nullptr
,则全局错误回调将调用此错误处理程序。你在调用 GLFW 函数之前设置这个指针,然后恢复它或使它无效。
请注意,这种简单的方法仅适用于单线程应用程序。如果您从多个线程调用 GLFW 函数,则需要确保线程安全。 GLFW 4 可能会对此进行改进。
我的 C++ 很生疏,所以不要指望它开箱即用,但我相信它展示了你可以做什么:
typedef void (*glfw_error_handler_function)(void* user_data, int error_code, const char* description);
thread_local static struct glfw_error_handler_t {
void* user_data;
glfw_error_handler_function handler;
} glfw_error_handler = { NULL, NULL };
static void global_glfw_error_handler(int error_code, const char* description) {
if (glfw_error_handler.handler != NULL) {
glfw_error_handler.handler(glfw_error_handler.user_data, error_code, description);
}
}
class Window {
private:
GLFWwindow* window;
void errorCallback(int error, const char* description) {
std::cerr << "Error: " << description << std::endl;
}
public:
Window() {
window = glfwCreateWindow();
// error handling omitted for simplicity
}
void requestAttention() {
glfw_error_handler_t previousState = glfw_error_handler;
glfw_error_handler.user_data = this;
glfw_error_handler.handler = Window::errorCallback;
glfwRequestWindowAttention(window);
// Restore previous error handler state
glfw_error_handler = previousState;
}
}
static int main() {
glfwSetErrorCallback(global_glfw_error_handler);
if (!glfwInit()) {
return EXIT_FAILURE;
}
Window window();
window.requestAttention();
return 0;
}
另一种可能性是在全局错误处理程序中抛出 C++ 错误,并在调用有问题的 GLFW 函数的位置捕获它。