1

So I'm currently writing a C++ OpenGL program and I'm fairly new in the language. What is a method called that has no parenthises?

My code block:

Program.cpp:

Input input;

glfwSetKeyCallback(window, input.HandleInput); //On this line input.HandleInput is the question at hand

Input.h

class Input
{
public:
    void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
};

Input.cpp

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>

#include "Input.h"

void Input::HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods)
{

     if (key == GLFW_KEY_F && action == GLFW_PRESS)
     {
         std::cout << key << " pressed.";
     }

}

Also i'd appreciate it if someonw would tell me how i could correctly execute the input.HandleInput method.

  • 1
    In general, you cannot use *pointer-to-member-function* where a *pointer-to-function* is expected. You need a global or a `static` member function. – Yksisarvinen Dec 17 '19 at 16:35
  • Does this answer your question? [What is a C++ delegate?](https://stackoverflow.com/questions/9568150/what-is-a-c-delegate) – Brandon Lyons Dec 17 '19 at 16:37
  • It might be intresting for you looking at the declaration of `glfwSetKeyCallback` – and specifically at the second parameter... – Aconcagua Dec 17 '19 at 16:39
  • 1
    `input.HandleInput` is simply not valid. It's not called anything because it's not a thing you can do. If it was a global function (outside of a class) then you would want to look up *function pointers* (`HandleInput` would not be a function pointer, but that's what you should learn about) – user253751 Dec 17 '19 at 16:41
  • [Comments are for getting clarification or suggesting edits/changes to the post](https://stackoverflow.com/help/privileges/comment). Please do not use them just to offer partial answers. – Xirema Dec 17 '19 at 16:49

1 Answers1

1

The method glfwSetKeyCallback takes a Function Pointer as its argument. Function Pointers are a relatively essential part of C and C++ functionality, and are the common idiom for implementing callbacks, as seen in this case.

What GLFW will do with the function passed to it is it has an internal polling functionality for system events (which you invoke using glfwPollEvents();) that, upon encountering a system event, will translate it into a system-agnostic form that can be interpreted using the callback you provided.

However, GLFW is written in C, and cannot handle the more complex, advanced kinds of Function Pointers or Functors that are native to C++, so when we pass a Function Pointer to GLFW, we need to reduce it down to a simpler form. A Member function of an object won't cut it. This is because a method like this:

class Input
{
public:
    void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
private:
};

Secretly, according to the compiler, actually looks like this:

void Input__HandleInput(Input * ptr, GLFWwindow* window, int key, int scancode, int action, int mods);

And since this signature does not match what GLFW is expecting for the callback, it will not accept it.

If you intend to use a class function as a callback for this function, you'll need to make it static.

struct Input {//'class' is fine, but 'struct' reduces boilerplate
    static void HandleInput(GLFWwindow* window, int key, int scancode, int action, int mods);
};

int main() {
    glfwInit();
    GLFWWindow* window = glfwCreateWindow(/*...*/);
    glfwSetKeyCallback(window, Input::HandleInput);
}

This may, however, represent a problem for you. After all, you probably wrote a class for this callback functionality specifically to offer some encapsulation of the behavior you need. Being forced to revert to using a static function or a global function defeats this purpose.

Instead, you need to use the User Pointer functionality that GLFW integrates.

struct InputHandler {
    static void HandleKey(GLFWwindow* window, int key, int scancode, int action, int mods) {
        //Perfectly legal: we fully intend to only permit the User Pointer to be of type 'InputHandler*'
        InputHandler & handler = *reinterpret_cast<InputHandler*>(glfwGetWindowUserPointer(window));
        handler.handleKeyImpl(window, key, scancode, action, mods);
    }
    void handleKeyImpl(GLFWwindow* window, int key, int scancode, int action, int mods) {
        /*...*/
    }
};

int main() {
    glfwInit();
    InputHandler input;
    GLFWWindow* window = glfwCreateWindow(/*...*/);
    glfwSetWindowUserPointer(window, &input);
    glfwSetKeyCallback(window, Input::HandleInput);
}
Xirema
  • 19,889
  • 4
  • 32
  • 68