当前位置: 首页 > 知识库问答 >
问题:

使用lambda作为GLFWkeyfun

饶德元
2023-03-14

对于我的一个项目,我使用GLFW3。我试着给函数GLFWSetKeyCallback一个c11 lambda,它把一个GFLWwindow和一个GLFWfunkey函数作为参数,这是一个要作废的typedef(*GLFWkeyfun)(GLFWwindow*,int,int,int,int)。

该函数是从我的窗口类调用的,下面是代码

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_;
};

还有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();
}

和来自编译器的错误(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);

有人能指出我做错了什么吗?

谢谢

共有3个答案

萧永望
2023-03-14

只有具有空捕获列表的lambdas可以转换为普通的旧函数指针。

所以,问题是

[this]

而不是

[]

但是如果你需要一个有状态的回调,那么你就不走运了。据我所知,这是不可能的,反正没有邪恶的体操是不行的。

也就是说,大多数C API提供了一个上下文指针,允许回调实际接收它应该工作的状态。似乎窗口参数就是您的示例中的参数。

方航
2023-03-14

无法将具有捕获的lambda转换为函数指针。函数指针是无状态的,它指向函数。具有捕获的lambda具有状态。它的行为就像一个物体。如果没有实例,则无法调用成员函数。这就是带有捕获的lambda不能转换为函数指针的方式。

您必须将函数更改为:

glfwSetKeyCallback(window_.get(), [](GLFWwindow* window, int key, int scancode, int action, int mode){ /* ... */ });

但是,您可以绕过无法访问此内容的限制。GLFW给了我们一种传递状态的方法。结构GLFWWindow包含一个可以自由更改和访问的无效*成员。

您可以这样做:

// 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);
    }
});
蒋奇
2023-03-14

正如krzaq所说,如果想要函数指针,就不能使用闭包。因此,您不能像您的示例中那样捕获

如果您仍然需要,则可以将其与GLFWwindow关联。我知道您可以使用以下API:glfwSetWindowUserPointer将GLFWwindow实例与窗口类的实例相关联。然后在回调中,您可以使用: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);
        });

 类似资料:
  • 我按照以下说明创建AWS Lambda层: 然后我压缩文件夹“python”()并将其上传到s3。这是我解压文件夹进行双重检查时看到的:

  • 如果我不使用' a '和' b '变量,一切正常,否则,C返回: 错误:无法转换“main()::” 注意:初始化'void f(int, void(*)(int))'的参数2

  • 我有一个简单的Micronaut Lambda应用程序,很难成功地将Mocks注入到我的单元测试中。 build.gradle 具有以下基本控制器 以及以下测试类别: 上面的测试将失败,因为模拟从未与之交互。 调试时,我可以看到在测试类本身中被模拟,但在类中使用了一个实际的对象。 我注意到,当我不使用(例如)时,这是预期的,所以我认为这与Lambda运行时有关,我希望有人能够指出我在正确的方向上。

  • 我是Kotlin的新手,很难理解下面的代码 所以这个函数叫做,它的输入参数是一个名为的函数,它是

  • 问题内容: 我有一张包含键和值的地图。我需要使用以下特定格式将其转换为。现在,我用来格式化每个元素,将它们收集到一个List中,然后执行String.join();。 有什么更短的方法吗?使用lambda会很好,因为我需要一些使用lambda的练习。 问题答案: 我认为您正在寻找这样的东西: 依次进行以下操作: 获取一个可迭代的条目序列 为此迭代创建一个流 将该条目流转换为“键-值”形式的字符串流

  • 我试图编写一个接受两个参数的函数,和。然后,它应该按照中给出的顺序对进行排序。例如,如果是,是,则函数应返回,排序中的顺序元素。 我按照下面的方式编写代码,但在arrays.sort处不断出现错误。我想我没有正确地使用lambda。你能具体说明我做错了什么吗?