在类中使用 GLFW 时,`<C++ class method>` 类型的参数与 `GLFWwindowsizefun` 类型的参数不兼容

问题描述 投票:0回答:3

我目前正在将代码重构为一个类(

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()

c++ callback glfw
3个回答
2
投票

成员函数原型

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


1
投票

让我们从收到的第一条错误消息开始。

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()
,您的第二个错误消息是抱怨。
    


0
投票

/* 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); }

© www.soinside.com 2019 - 2024. All rights reserved.