📅 2015-Sep-01 ⬩ ✍️ Ashwin Nanjappa ⬩ 🏷️ callback, glfw, glut, opengl ⬩ 📚 Archive
A typical problem when using a C library with your own C++ code: the library requires a C callback function pointer, but you want to pass your C++ class method (that is non-static) to it.
I face this problem when using C libraries like GLFW or GLUT, which provide an interface to OpenGL, which is also a C library. For example, say I want to register a C++ class method with GLFW as callback for mouse button event. GLFW expects me to pass it a C function pointer with this signature:
void ButtonCallback(GLFWwindow*, int, int, int);
// Register above function as callback
glfwSetMouseButtonCallback(window, ButtonCallback);
I want to register this C++ class method as the callback:
class Foo
{
public:
Foo()
{
// Error!
glfwSetMouseButtonCallback(window, FooButtonCallback);
}
void FooButtonCallback(GLFWwindow*, int, int, int)
{ /* something */ }
};
No pointer trickery can make it work because the signature of a C++ class non-static method is different from a C callback.
One solution is to only use C++ class static methods as callback. These can be passed as C callback because these are nothing but C functions with a glorified name. However, this causes serious problems later when you want update some class variable with the data received from the callback.
The solution I use in such a scenario is an ugly hack called trampoline. The idea is to create a global C function which can be passed as callback and inside it call the C++ method by using its object pointer:
Foo* g_foo_ptr = nullptr;
void TrampButtonCallback(GLFWwindow* a, int b, int c, int d)
{
if (g_foo_ptr) // Check before calling
g_foo_ptr->FooButtonCallback(a, b, c, d);
}
class Foo
{
public:
Foo()
{
g_foo_ptr = this; // Store global
glfwSetMouseButtonCallback(window, TrampButtonCallback);
}
void FooButtonCallback(GLFWwindow*, int, int, int)
{ /* something */ }
};