5

I have an class with instance functions (or methods?). From within an instance, I try to pass pointers to those functions to a library. The library expects static functions.

When I pass my pointers to the callback functions, the compiler complains that my functions are not static. I tried to put make them static, but if I do so, then I can't access the instance fields from within the functions.

How could I go around this?

Similar question is : Using a C++ class member function as a C callback function where they suggest to put the method static. However I can't do that, or I don't see how I could.

Code

GlutController::GlutController (int argc, char **argv) {

   // stuff ..

   // Register callbacks
   glutSpecialFunc( OnSpecialKeys );  // Error, need static functions
   glutReshapeFunc( OnChangeSize );   // Error...
   glutDisplayFunc( OnRenderScene );  // Error...

   // stuff ..
}

GlutController::~GlutController() {

}

void GlutController::OnChangeSize(int aNewWidth, int aNewHeight){

   glViewport(0,0,aNewWidth, aNewHeight);
   mViewFrustrum.SetPerspective( APP_CAMERA_FOV,             // If this function is 
            float( aNewWidth ) / float( aNewHeight ),        // static, this won't 
            APP_CAMERA_NEAR,                                 // work
            APP_CAMERA_FAR );
   mProjectionMatrixStack.LoadMatrix(                        // Same here
            mViewFrustrum.GetProjectionMatrix() );
   mTransformPipeline.SetMatrixStacks(mModelViewMatrixStack, // Same here  
            mProjectionMatrixStack);

}

void GlutController::OnRenderScene(void){
   mGeometryContainer.draw();                                // Won't work if static
}

void GlutController::OnSpecialKeys(int key, int x, int y){
   mGeometryContainer.updateKeys(key);                       // Won't work if static
}

Disclaimer : I just begun C++. I read all of Accelerated C++ and this is my first project to try out the language. My background is in Java.

Community
  • 1
  • 1
AntoineG
  • 1,217
  • 2
  • 15
  • 24

4 Answers4

7

What you are trying to do is not possible. This is glut's fault actually.

The thing is this:

  • glut wants to call a function, without giving it data,
  • You want your function to use some data,

which are conflicting needs. I believe glut decided you can safely use global variables.

So, one solution is to use static functions, with static data. Or a better solution would be to switch to SDL.

Shahbaz
  • 42,684
  • 17
  • 103
  • 166
  • I don't know much about glut, but it sounds like it requires something callable, that doesn't take any arguments (implicit ones included). So wouldn't a suitably constructed `std::function` do the trick? – juanchopanza Aug 03 '12 at 09:31
  • 2
    Anyone who develops a opaque library function that cannot take a user-defined parameter, (eg. for use in callbacks), should be fired, promoted to marketing/sales or given a financial incentive to go work for a rival company. – Martin James Aug 03 '12 at 09:58
  • @Shahbaz I'm trying to make a simple demo, and I read that glut was very simple to use compared to SDL in term of boilerplate code. Also I'm using the book 'OpenGL SuperBible' to guide me. I think using static/global will be inevitable, or use a Singleton like Nick said in his answer below. – AntoineG Aug 03 '12 at 12:15
  • @MartinJames, agreed. And [it's not just that!](http://en.wikipedia.org/wiki/OpenGL_Utility_Toolkit#Limitations). I think at the time glut was designed, people were not so good at foreseeing. Either that, or microsoft had a part in it. – Shahbaz Aug 03 '12 at 13:08
  • @AntoineG, All you need to do extra with SDL is to write a 3 line main loop and remove all the giving callback lines, and a `while/select` that calls your functions based on the events from a queue. Believe me, if you want to go just beyond drawing a couple of triangles, glut becomes very hard to control. By the way, I also learned openGL from the same book, but replacing the glut code with SDL, the focus is more on the openGL part, so it shouldn't get in your way. – Shahbaz Aug 03 '12 at 13:10
3

In short, you can't. C++ member functions are actually 'linked' to the instance of the object. On the lower level, they have one extra parameter, which is actually the pointer to the instance of this object.

So, you have to use static function, and, since glut wouldn't let you to pass a parameter which would identify the current instance, you will have to come up with some workaround. The simplest workaround would be to use static members. If your GlutController is singleton (and I think it is), you'll be fine.

Senna
  • 198
  • 4
2

It is possible and apparently safe to use a file scoped static variable pointing to your GlutInstance (static function + static data, like mentioned in another answer).

static GlutController* s_this;

static void s_OnChangeSize(int w, int h) { s_this->OnChangeSize(w, h); }

GlutController::GlutController (int argc, char **argv) { 
   s_this = this;

   glutSpecialFunc(s_OnSpecialKeys);
}

GlutController::~GlutController() { s_this= 0; } 

void GlutController::OnChangeSize(int w, int h) { /* non-static stuff */ }

s_this is only visible in the local file, e.g. not visible to any code that invokes the GlutController constructor from another file.

Nick
  • 5,655
  • 5
  • 25
  • 35
1

you should have a static method and an instance (possibly static) to call a member function of instance from static function

Something like this:

//static method
void MyClass::myCallback()
{
    static MyClass instance; //or you can store your in instance in some Singleton, or
    //possibly create a temporary
    instance.nonStaticMethod();
}
Andrew
  • 22,844
  • 11
  • 57
  • 88