0
votes

I'm creating a GLFWKeyCallback and because of how simple it is I've decided to use a lambda. This callback modifies a member variable, so I have to pass this into the capture list. Here is what my code looks like so far:

glfwSetKeyCallback(window, 
        [this](GLFWwindow* window, int key, int scancode, int action, int mods)
        {
            if(action == GLFW_PRESS)
            {
                 //use a mutex
                 //Modify member variable
            }
        });

The problem is that whenever I pass this into the capture list, Visual Studio 2019 displays the following error:

no suitable conversion function from "lambda [] void (GLFWwindow *window, int key, int scancode, int action, int mods)->void" to GLFWKeyfun" exists

Have I missed something or is this code just invalid?

1
glfwSetKeyCallback doesn't take a lambda - it takes a plain old function pointer. A capture-less lambda is convertible to a function pointer; a lambda with captures is not (there's no place to store captured data in). - Igor Tandetnik
Does this answer your question? Passing C++ method as function pointer. My answer there shows the messy nature of using a member function where a bare function is called for. - Spencer
you can use glfwSetWindowUserPointer to give the window a user-defined pointer (like whatever this is) and use glfwGetWindowUserPointer to get it back from within the callback - kmdreko
I'd just finished composing an answer demonstrating glfwSetWindowUserPointer when the question closed :( Still, yes, setting and retrieving this as the window pointer is the correct method. - N. Shead
My answer there shows a way around your problem. The point is that you need an instance of the class to alter the member variable. A lambda with captures will never work -- it's a class created on the fly with the function pointer and the capture values as data members. - Spencer

1 Answers

3
votes

The GLFW callbacks don't take lambdas, or function objects: they take plain old function pointers. A non-capturing lambda can be converted to a function pointer, but not a capturing one.

However, you can get a similar effect by using glfwSetUserPointer and glfwGetUserPointer. The lambda still can't be capturing, but you can recover the this pointer.

For example,

struct MyClass {
  GLFWwindow* window;

  MyClass(GLFWwindow* window) : window(window) {
    glfwSetWindowUserPointer(window, static_cast<void*>(this));

    glfwSetKeyCallback(window, 
      [](GLFWwindow* window, int key, int scancode, int action, int mods) {
        auto self = static_cast<MyClass*>(glfwGetWindowUserPointer(window));
        // can access member variables through `self`
      });
  }

  // make sure that either the class will last as long as GLFW will
  // or clean up the user pointer and callbacks in here
  ~MyClass() {
    // clean up
  }

  // don't be able to copy, probably, or bad things will happen
  MyClass(const MyClass&) = delete;
  MyClass& operator=(const MyClass&) = delete;
  // other things...
};