1

I've created a class called InputControl. I am using a library called GLFW, and a function glfwSetKeyCallback. The function is defined as:

GLFWkeyfun glfwSetKeyCallback ( GLFWwindow * window, GLFWkeyfun cbfun )

Typedef is as follows:

typedef void(* GLFWkeyfun) (GLFWwindow *, int, int, int, int)

The issue is that I can not convert my method to a function pointer. I feel like I've tried to cast it in every way possible. I'm not sure how else I need to cast this method. Is there something that is specific for passing a relative method as a function pointer? My code is as follows:

#pragma once
#include <GLFW/glfw3.h>
#include "config.h"

class InputControl {
public:
    void bind();
    void unbind();

private:
     void __glfw__keycallback_bind(GLFWwindow* window, int key, int scancode, int action, int mods);
};

InputControl.cpp

void InputControl::bind() {
    glfwSetKeyCallback(__application__window, __glfw__keycallback_bind);
}

void InputControl::unbind() {

}

void InputControl::__glfw__keycallback_bind(GLFWwindow * window, int key, int scancode, int action, int mods) {
//... other code here
}

Visual Studio gives me the following error

E0167 argument of type "void (InputControl::*)(GLFWwindow *window, int key, int scancode, int action, int mods)" is incompatible with parameter of type "GLFWkeyfun"

NateAGeek
  • 624
  • 1
  • 8
  • 22
  • 4
    It is not possible to convert a non-static class method pointer to a regular function pointer. These are entities of completely different and incompatible nature. Just stop trying to do this. Your question, unfortunately, does not provide enough context to offer an alterantive solution. Where will the actual `InputControl` object reside? – AnT stands with Russia Jun 23 '17 at 00:34
  • 5
    Unrelated to your question, but don't define names or symbols using two leading underscores. Those are reserved for the compiler and standard library in all scopes. See [this old question and its answers](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) for more information. – Some programmer dude Jun 23 '17 at 00:36
  • Expanding on @AnT's comment. A method acts on ***an instance of a class***. A regular function has no way to determine which instance to act on. – Disillusioned Jun 23 '17 at 00:40

2 Answers2

6

A non-static member function needs an object to work on. You need a non-member function, or a static member function, as the callback. If you absolutely need to access an instance of your InputControl class inside the callback, you can set the window's user pointer using glfwSetWindowUserPointer(), and then the callback can use that pointer to call a non-static member function:

class InputControl {
public:
    void bind();
    void unbind();

private:
     static void keyCallbackStatic(GLFWwindow* window,
                                   int key,
                                   int scancode,
                                   int action,
                                   int mods);
     void keyCallback(GLFWwindow* window,
                      int key,
                      int scancode,
                      int action,
                      int mods);
};

void InputControl::bind() {
    glfwSetWindowUserPointer(applicationWindow, this);
    glfwSetKeyCallback(applicationWindow, keyCallbackStatic);
}

void InputControl::keyCallbackStatic(GLFWwindow* window,
                                     int key,
                                     int scancode,
                                     int action,
                                     int mods)
{
    InputControl* that = static_cast<InputControl*>(glfwGetWindowUserPointer(window));
    that->keyCallback(window, key, scancode, action, mods);
}

void InputControl::keyCallback(GLFWwindow* window,
                               int key,
                               int scancode,
                               int action,
                               int mods)
{
    // Do whatever
}

It's up to you to make sure your InputControl object stays alive for as long as your window, and that nothing else sets the window's user pointer to anything besides the InputControl object pointer.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
0

You could have an interface that calls your member function:

class App {
public:
    void onKeyDown(int key, int action) {
        if (action == 1)
            std::cout << "Pressed: " << static_cast<char>(key) << '\n';
        if (action == 0)
            std::cout << "Released: " << static_cast<char>(key) << '\n';
    }
};

class Interface {
public:
    static void* p;

    static void OnKeyDown(GLFWwindow * window, int key, int scancode, int action, int mods) {
        ((App*)(p))->onKeyDown(key, action);
    }
};
void * Interface::p;

int main()
{
    App app;

    [...]

    glfwSetKeyCallback(window, Interface::OnKeyDown);

}
Andreas DM
  • 10,685
  • 6
  • 35
  • 62