我目前正在将代码重构为一个类(
VkAPP
),并偶然发现了这个错误:
“void (VkAPP::)(GLFWwindow window, int width, int height)”类型的参数与“GLFWwindowsizefun”类型的参数不兼容
这是有问题的函数:
void onWindowResized(GLFWwindow* window, int width, int height) {
VkSurfaceCapabilitiesKHR surfaceCapabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevices[0], surface, &surfaceCapabilities);
if (width > surfaceCapabilities.maxImageExtent.width) width = surfaceCapabilities.maxImageExtent.width;
if (height > surfaceCapabilities.maxImageExtent.height) height = surfaceCapabilities.maxImageExtent.height;
if (width == 0 || height == 0) return;
WIDTH = width;
HEIGHT = height;
recreateSwapchain();
}
电话如下:
glfwSetWindowSizeCallback(window, onWindowResized);
函数和调用在同一个类中。
如果我把它变成:
static void onWindowResized
我得到:
非静态成员引用必须相对于特定对象
对于
physicalDevices[0]
、surface
、WIDTH
、HEIGHT
和 recreateSwapchain()
成员函数原型
void onWindowResized(GLFWwindow* window, int width, int height);
实际上看起来像这样
void onWindowResized(
MyClass *this, //the famously infamous 'this' pointer
GLFWwindow* window,
int width,
int height
);
要将函数用作回调,该函数必须是全局函数或在类中声明为静态。
为了将窗口与特定数据相关联,GLFW 提供了一种机制来完成此操作:
void glfwSetWindowUserPointer(GLFWwindow *window, void *pointer);
并通过
检索它void* glfwGetWindowUserPointer(GLFWwindow *window);
要完成所有工作,您必须进行一些修改:
//either global or inside class
static void onWindowResized(GLFWwindow* window, int width, int height)
{
//get your class instance
MyClass *obj = reinterpret_cast<MyClass*>(glfwGetWindowUserPointer(window));
//use the memebers as usual
//obj->physicalDevices[0];
//obj->surface;
//obj->WIDTH;
//obj->HEIGHT;
//obj->recreateSwapchain();
//note:
//if function is in global scope, the members have to be public
//if inside the class, private members can be accessed
}
不要忘记将类实例与窗口关联起来:
//somewhere in your code (but before the callback gets invoked)
glfwSetWindowUserPointer(window, /* MyClass* */ obj);
注意:密切关注类实例的生命周期
obj
。
让我们从收到的第一条错误消息开始。
GLFWwindowsizefun
的定义如下:
typedef void(* GLFWwindowsizefun) (GLFWwindow *window, int width, int height)
另一方面,C++ 类的(非静态)
onWindowResized
方法有一个隐式类实例指针。
换句话说,你的
VkAPP
C++ 类的非静态 onWindowResized
方法声明如下:
// Inside VkAPP class
void onWindowResized(GLFWwindow* window, int width, int height)
有一个隐式参数,它是指向
VkAPP
类实例的指针(即C++中经典的this
指针):
void VkAPP::onWindowResized( VkAPP* this, /* implicit VkAPP* 'this' pointer */ ,
GLFWwindow* window,
int width,
int height)
因此,C++ 编译器向您发出预期的 GLFWwindowsizefun
(没有隐式
this
指针)和您的 VkAPP::onWindowResized
方法(确实有隐式 this
指针)之间的 mismatch信号。 .
如何解决这种不匹配问题?
好吧,你可以在你的 VkAPP
C++ 类中定义一个
static方法,如下所示:
// Inside VkAPP class
//
// Note: the method is *static*
static void onWindowResizedStatic(GLFWwindow* window, int width, int height)
注意,
static
方法没有有隐式的this
指针,所以上面的方法对应于GLFWwindowsizefun
typedef
。
因此您可以将其传递给
glfwSetWindowSizeCallback
函数调用:
// You had this line, which didn't work as onWindowResized was not static:
//
// glfwSetWindowSizeCallback(window, onWindowResized); <<-- error
//
// Pass a *static* method as callback, instead:
//
glfwSetWindowSizeCallback(window, onWindowResizedStatic);
不幸的是,正如您收到的其他错误消息所示,您无法从您的 static 方法访问
特定于实例的数据成员,例如
physicalDevices[0]
、
surface
、
WIDTH
、
HEIGHT
等)类。
因此,这里的想法是使用 static
方法作为将调用转发到类的实例特定方法的位置,例如:
// Inside VkAPP class
static void onWindowResizedStatic(GLFWwindow* window, int width, int height) {
// Somehow get the instance-specific "this" pointer
VkAPP* pThis = ... /* we'll see that later */;
// Forward the call to the non-static method callback:
pThis->onWindowResized(window, width, height);
}
现在,如何从上面的 this
方法中检索
static
指针?嗯,在初始化期间(例如,在 C++ 类的构造函数中,或在另一个初始化方法中),您可以调用
glfwSetWindowUserPointer
函数来set 特定于实例的
this
指针作为关联的通用“用户指针”到窗边:
// Inside a method of your VkAPP C++ class, during initialization:
// Set the "this" pointer as window's user pointer for later retrieval
glfwSetWindowUserPointer(window, this);
然后,稍后可以调用对称 this
:来检索
glfwGetWindowUserPointer
指针
// Inside VkAPP class
static void onWindowResizedStatic(GLFWwindow* window, int width, int height) {
// Get the instance-specific "this" pointer
// that was set before during initialization
VkAPP* pThis = reinterpret_cast<VkAPP*>(glfwGetWindowUserPointer(window));
// Forward the call to the non-static method callback:
pThis->onWindowResized(window, width, height);
}
请注意,由于您的 onWindowResized
方法不是静态,因此您可以使用所有特定于实例的数据成员,例如
physicalDevices[0]
、surface
等,或调用其他成员函数,例如 recreateSwapchain()
,您的第二个错误消息是抱怨。/* Resizes the Window when Size changes */
static void windowResizeStatic(GLFWwindow* window, int width, int height) {
Engine* pThis = static_cast<Engine*>(glfwGetWindowUserPointer(window));
pThis->onWindowResized(width, height);
}
void onWindowResized(int width, int height) {
/* rest of the function cut out */
}
void startGLFW() {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Window Name", nullptr, nullptr);
//set the glfwSetWindowUserPointer here or it returns a nullptr
glfwSetWindowUserPointer(window, this);
glfwSetWindowSizeCallback(window, windowResizeStatic);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}