Reputation: 376
I have a class as follows and a main method as follows:
class Mesh
{
public:
void draw()
void draw(){}
}
int main(int argc,char* argv[])
{
Mesh mesh;
glutDisplayFunc(mesh.draw);
}
So I want to pass a member function of an object as argument, but the compiler displays the following error message:
error: argument of type ‘void (Mesh::)()’ does not match ‘void (*)()’
What am I doing wrong?
Upvotes: 0
Views: 1185
Reputation: 514
Since draw
is a non-static member function, it needs an instance of the class to operate upon.
In pure C++, you would use a function object (a.k.a. "functor", see std::function
or its predecessor boost::function
). That's sadly not an option in C or C APIs.
In this case, since there's no data that is handed to the callback, you must make some sort of static function (either class static or file static) that does the right thing when it is called.
If you only ever have one Mesh
, then it's easy: either make everything in the class static (in which case it's basically a namespace), or have a non-member function that calls draw
against the one instance of your Mesh
:
// at some global-ish file scope...
// we define our class
class Mesh { ... };
// and here's the one global instance of it
Mesh myOneMesh;
// and here is our global / static function that "knows"
// which instance to draw
void drawMyOneMesh() { myOneMesh.draw(); }
// then, in the main flow of your program:
glutDisplayFunc( &drawMyOneMesh );
If you have multiple meshes, it looks like the best you can do is to key it off of the current window. Without knowing much about your app or about the GLUT API, I would probably do something like this to enable a mesh-per-window callback:
#include <map>
// this could also be a class with all-static members, if one
// were so inclined. might be worth it, if only to protect 'map'
// from external meddling.
namespace WindowToMesh
{
typedef std::map< int, Mesh * > Map;
Map map;
void addMapping( int win, Mesh * mesh )
{
map.insert( { win, mesh } );
}
void removeMapping( int win )
{
map.erase( win );
}
void draw()
{
int win = glutGetWindow();
Map::iterator it = map.find( win );
if ( it != map.end() )
it.second->draw();
}
} // end namespace WindowToMesh
Now, in your main program, you can associate a new Mesh
with the current window:
Mesh * m = new Mesh( ... );
WindowToMesh::addMapping( glutGetWindow(), m );
And you can associate the (effectively static) WindowToMesh::draw
function as the callback:
glutDisplayFunc( &WindowToMesh::draw );
When you're ready to destroy the Mesh
, make sure you're in the same window, and then:
WindowToMesh::removeMapping( glutGetWindow() );
Depending on other factors, it might make sense to do a bidirectional mapping (so you can find things by Mesh *
and not just by window int
, or to do a brute-force scan on the rare unregistration, etc.
I don't have an environment in which I can test that, but it should be close. Good luck!
Upvotes: 2
Reputation: 45675
The problem is that a member function pointer needs some information to be called, i.e. the instance to be called on, which will then be accessible by the this
pointer within the implementation of the member function, so you can access member variables. I think you want to do this, since your design looks like you want to draw stuff which is defined in Mesh
.
There are possibilities to turn a member function pointer into a "normal" function pointer. But you have to keep in mind that this piece of information (the instance of Mesh
) has to be available once this function is called. This means that a typical transformation from a member function pointer to a "normal" function pointer adds a parameter (the instance).
But glutDisplayFunc()
accepts a void(*)(void)
function pointer, i.e. an empty parameter list, so it won't tell the called function anything. You have to make sure that once the passed function is called, you can howsoever reconstruct the "context", i.e. the Mesh
instance.
This can be done by pointing to a Mesh
instance from a global point in your code. It will always be used when you call the helper function we are about to write. So when you pass a pointer to glutDisplayFunc()
our helper function knows which Mesh
to use, once we told it which it should use.
class Mesh
{
public:
void draw() { ... }
}
Mesh *instance;
// Helper function called by glut:
void display() {
// Now we can access a particular instance:
instance->draw();
}
int main(int argc,char* argv[])
{
Mesh mesh;
// First point to this instance globally:
instance = &mesh;
// Then, pass our helper function which now has an empty parameter list:
glutDisplayFunc(&display);
}
This solution has a restriction. You can't reuse the same function pointer with different instances. So you can't turn any instance into a function pointer, but only one for each globally defined instance pointer. But since you just want to pass your draw function to glutDisplayFunc
, you only need to do this once, so it should be fine. I just don't want to keep this "danger" from you. ;)
Upvotes: 1