Reputation: 155
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?
Upvotes: 0
Views: 906
Reputation: 31
Adding onto the other answer.
I see glfwSetWindowUserPointer brought up a lot as a solution to this issue. It works fine (and I use it myself, since I don't know of any other solution), but it comes with a caveat that I haven't seen anyone mention:
You can only store one pointer per Window using this method. If some other code sets a different pointer to your window, all of a sudden your lambda won't work anymore. I can think of two workarounds here:
When you retrieve the pointer in your lambda body, set it to a static variable. This way, it will persist across calls to the lambda, even if someone else sets a different pointer. Note: the static variable won't initialize until the first call to the lambda, so you'd be best to call the lambda once, yourself, after defining it.
Define a object or map of pointers. Give GLFWSetUserPointer a pointer to that map. I can't think of any way to enforce this pattern, but if you have complete control over your app, you can store multiple pointers in associated with a Window this way.
Upvotes: 1
Reputation: 3938
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...
};
Upvotes: 7