对于我的一个项目,我使用的是 GLFW3。我正在尝试为函数GLFWSetKeyCallback提供 C++11 lambda,该函数将 GFLWwindow 和 GLFWfunkey 函数作为参数,该函数是 void(* GLFWkeyfun) (GLFWwindow *, int, int, int, int) 的 typedef )。
该函数是从我的 Window 类调用的,这是代码
窗口.hpp
class Window
{
public:
Window(GLuint width, GLuint height, std::string title);
~Window();
GLFWwindow* get() { return window_.get(); }
bool is_open() { return open_; };
void close();
private:
bool open_ = false;
std::unique_ptr<GLFWwindow, DestroyWindow> window_;
std::vector<Drawable*> drawables_;
};
Run Code Online (Sandbox Code Playgroud)
和window.cpp
#include <pck/window.hpp>
Window::Window(GLuint width, GLuint height, std::string title) :
open_(true)
{
window_.reset(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr));
glfwMakeContextCurrent(window_.get());
Global::width = width;
Global::height = height;
glfwSetKeyCallback(window_.get(), [this](GLFWwindow* window, int key, int scancode, int action, int mode){
for(auto it : drawables_)
it->input(window, key, scancode, action, mode);
});
}
Window::~Window()
{
window_.reset();
}
void
Window::close()
{
open_ = false;
window_.reset();
}
Run Code Online (Sandbox Code Playgroud)
以及来自编译器的错误(clang++ 3.8.1)
fatal error: no matching function for call to 'glfwSetKeyCallback'
glfwSetKeyCallback(window_.get(), [this](GLFWwindow* window, i...
^~~~~~~~~~~~~~~~~~
/usr/include/GLFW/glfw3.h:3307:20: note: candidate function not viable: no
known conversion from '(lambda at
/path/to/file.cpp)' to
'GLFWkeyfun' (aka 'void (*)(GLFWwindow *, int, int, int, int)') for 2nd argument
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun);
Run Code Online (Sandbox Code Playgroud)
有人可以指出我做错了什么吗?
谢谢!
正如 krzaq 所说,如果您想要函数指针,则不能使用闭包。所以你不能this像你的例子那样捕获。
如果您this无论如何都需要,那么您可以将它与您的GLFWwindow. 我看到您可以使用此 API:glfwSetWindowUserPointer将 GLFWwindow 实例与您的Window类的实例相关联。然后在您的回调中,您可以使用以下命令检索它:glfwGetWindowUserPointer。
所以你的代码看起来像(伪代码):
glfwSetWindowUserPointer(window_.get(), this);
glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){
Window* pw = (Window*)glfwGetWindowUserPointer(window);
for(auto it : pw->drawables_)
it->input(window, key, scancode, action, mode);
});
Run Code Online (Sandbox Code Playgroud)
具有捕获的 lambda 不能转换为函数指针。函数指针是无状态的,它指向一个函数。带有捕获的 lambda 有一个状态。它的行为就像一个对象。没有实例就不能调用成员函数。这就是无法将带有捕获的 lambda 转换为函数指针的方式。
您必须将您的功能更改为:
glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){ /* ... */ });
Run Code Online (Sandbox Code Playgroud)
但是,您可以绕过无法访问它的限制。GLFW 为我们提供了一种传递状态的方法。该结构GLFWWindow包含一个void*您可以自由更改和访问的成员。
你可以做的是这样的:
// Here we are setting the user pointer to `this`
glfwSetWindowUserPointer(window_.get(), this);
glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){
// Here we retrieve the pointer we setted before. It will be equal to `this`
auto& self = *static_cast<Window*>(glfwGetWindowUserPointer(window));
for(auto&& it : self.drawables_) {
it->input(window, key, scancode, action, mode);
}
});
Run Code Online (Sandbox Code Playgroud)
只有具有空捕获列表的 lambda 才可以转换为普通的旧函数指针。
所以,问题是
[this]
Run Code Online (Sandbox Code Playgroud)
代替
[]
Run Code Online (Sandbox Code Playgroud)
但如果您需要有状态的回调,那么您就不走运了。据我所知,这是不可能的,无论如何,如果没有邪恶的体操,这是不可能的。
话虽这么说,大多数 C API 都提供了一个上下文指针,允许回调实际接收它应该处理的状态。看来该window参数就是您示例中的参数。
| 归档时间: |
|
| 查看次数: |
2647 次 |
| 最近记录: |