在 C++ 中隐藏来自第 3 方库的回调原型
Hide callback prototype from a 3rd party library in C++
我正在使用具有此函数 glfwSetCursorPosCallback
的 glfw3 库,要使用该函数,您需要传递一个 GLFWwindow
指针和一个指向此原型函数的指针 void callback(GLFWwindow* window, double, double)
.
我想创建一个 class WindowManager,它封装了该库的所有操作,所以我将 GLFWindow
保存为变量成员,并试图隐藏对 [=14 的调用=] 在 void WindowManager::setCursorCallback(void (*callback)(double, double))
void WindowManager::aCursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
this->cursorPosCallback(xpos, ypos);
}
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
glfwSetCursorPosCallback(this->window, this->aCursorPosCallback);
}
所以 WindowManager
的客户端不必保留对 GLFwindow
的引用,像这样:
static void cursor_pos_callback(double xpos, double ypos)
{
// HERE I have access to the values I care xpos and ypos
}
int main(int argc, char **argv) {
WindowManager *wm = new WindowManager();
wm->createWindow(WIDTH, HEIGHT)
wm->setCursorCallback(cursor_pos_callback);
}
此代码无法编译,因为我试图像传递静态函数一样传递成员函数,但如果我可以修改第 3 方代码,我该如何实现此行为?
我什至尝试使用 labdas 但没有成功,编译器说 lambdas 只能在不捕获的情况下进行转换,所以我坚持使用它,任何线索都会有所帮助。
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
auto lamda =
[callback](GLFWwindow* window, double xpos, double ypos)
{
printf("this works if no capture the callback");
// callback(xpos, ypos);
};
glfwSetCursorPosCallback(this->window, (void(*)(GLFWwindow* window, double xpos, double ypos)) lamda);
}
更新:
基于@SparkyPotato 的评论,这应该有效并且确实有效。在使用 window、glfwSetWindowUserPointer(this->window, this);
将 WindowManager 设置为用户指针之前
static void aCursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
WindowManager *wm = (WindowManager *) glfwGetWindowUserPointer(window);
wm->cursorPosCallback(xpos, ypos);
}
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
glfwSetCursorPosCallback(this->window, aCursorPosCallback);
}
GLFW 允许您设置一个 window 用户指针,可以是任何 void*
。然后您可以检索 void*
,并将其转换为您想要的任何类型。我认为函数为 glfwSetWindowUserPointer()
和 glfwGetWindowUserPointer()
.
你可以做的是让 WindowManager
注册所有回调,并将用户指针设置为 this
。然后,当用户希望设置某些内容时,您可以在 WindowManager
本身中使用 std::function
(这样他们就可以传递 lambda 或任何他们想要的东西),然后从您的 GLFW 回调中调用该函数reinterpret_cast
将 window 用户指针指向 WindowManager
。
示例:
class WindowManager
{
public:
template<typename T>
void SetCursorPosCallback(const T& userCallback)
{
m_UserCallback = userCallback;
}
void CreateWindow(/* args */)
{
GLFWwindow* window = glfwCreateWindow(/* args */);
glfwSetWindowUserPointer(window, this);
glfwSetCursorPosCallback(window, &WindowManager::CursorPosCallback);
}
private:
static void CursorPosCallback(GLFWwindow* window, double x, double y)
{
WindowManager* manager = reinterpret_cast<WindowManager*>(glfwGetWindowUserPointer(window));
manager.m_UserCallback(x, y);
}
std::function<void(double, double)> m_UserCallback;
};
我正在使用具有此函数 glfwSetCursorPosCallback
的 glfw3 库,要使用该函数,您需要传递一个 GLFWwindow
指针和一个指向此原型函数的指针 void callback(GLFWwindow* window, double, double)
.
我想创建一个 class WindowManager,它封装了该库的所有操作,所以我将 GLFWindow
保存为变量成员,并试图隐藏对 [=14 的调用=] 在 void WindowManager::setCursorCallback(void (*callback)(double, double))
void WindowManager::aCursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
this->cursorPosCallback(xpos, ypos);
}
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
glfwSetCursorPosCallback(this->window, this->aCursorPosCallback);
}
所以 WindowManager
的客户端不必保留对 GLFwindow
的引用,像这样:
static void cursor_pos_callback(double xpos, double ypos)
{
// HERE I have access to the values I care xpos and ypos
}
int main(int argc, char **argv) {
WindowManager *wm = new WindowManager();
wm->createWindow(WIDTH, HEIGHT)
wm->setCursorCallback(cursor_pos_callback);
}
此代码无法编译,因为我试图像传递静态函数一样传递成员函数,但如果我可以修改第 3 方代码,我该如何实现此行为?
我什至尝试使用 labdas 但没有成功,编译器说 lambdas 只能在不捕获的情况下进行转换,所以我坚持使用它,任何线索都会有所帮助。
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
auto lamda =
[callback](GLFWwindow* window, double xpos, double ypos)
{
printf("this works if no capture the callback");
// callback(xpos, ypos);
};
glfwSetCursorPosCallback(this->window, (void(*)(GLFWwindow* window, double xpos, double ypos)) lamda);
}
更新:
基于@SparkyPotato 的评论,这应该有效并且确实有效。在使用 window、glfwSetWindowUserPointer(this->window, this);
static void aCursorPosCallback(GLFWwindow* window, double xpos, double ypos)
{
WindowManager *wm = (WindowManager *) glfwGetWindowUserPointer(window);
wm->cursorPosCallback(xpos, ypos);
}
void WindowManager::setCursorCallback(void (*callback)(double, double)) {
this->cursorPosCallback = callback;
glfwSetCursorPosCallback(this->window, aCursorPosCallback);
}
GLFW 允许您设置一个 window 用户指针,可以是任何 void*
。然后您可以检索 void*
,并将其转换为您想要的任何类型。我认为函数为 glfwSetWindowUserPointer()
和 glfwGetWindowUserPointer()
.
你可以做的是让 WindowManager
注册所有回调,并将用户指针设置为 this
。然后,当用户希望设置某些内容时,您可以在 WindowManager
本身中使用 std::function
(这样他们就可以传递 lambda 或任何他们想要的东西),然后从您的 GLFW 回调中调用该函数reinterpret_cast
将 window 用户指针指向 WindowManager
。
示例:
class WindowManager
{
public:
template<typename T>
void SetCursorPosCallback(const T& userCallback)
{
m_UserCallback = userCallback;
}
void CreateWindow(/* args */)
{
GLFWwindow* window = glfwCreateWindow(/* args */);
glfwSetWindowUserPointer(window, this);
glfwSetCursorPosCallback(window, &WindowManager::CursorPosCallback);
}
private:
static void CursorPosCallback(GLFWwindow* window, double x, double y)
{
WindowManager* manager = reinterpret_cast<WindowManager*>(glfwGetWindowUserPointer(window));
manager.m_UserCallback(x, y);
}
std::function<void(double, double)> m_UserCallback;
};