1

I'm separating my code into multiple files, but this is one thing I don't get.

In graphics.h:

...
class graphics {
public:
virtual void SizeMod(int w, int h);
...
}

In graphics.cpp:

...
void SizeMod(int w, int h) {
    //Code here.
}
...

In main.cpp:

...
graphics g;
...
int main (int argc, char **argv) {
    ...
    glutReshapeFunc(g.SizeMod);
    ...
}

Error:

error C3867: 'graphics::SizeMod': function call missing argument list; use &graphics::SizeMod to create a pointer to member

And so I did that:

...
graphics g;
...
int main (int argc, char **argv) {
    ...
    glutReshapeFunc(&graphics::SizeMod);
    ...
}

It still gives me an error (a different one). Anything to solve this problem?

2 Answers2

1

GLUT is a C API. glutReshapeFunction expects a callback to a function of the signature

void (int, int)

A C++ class member function, in your case graphics::SizeMod has the signature

graphics::void(int, int)

Now, there's no well defined C++ ABI that could be strictly translated into the commonplace C ABI, but for all practical means on most compilers the C++ signature from above looks like

void(graphics*, int, int)

if looked through the glasses of a C ABI.

This first graphics* parameter that's the implicit this pointer.

Which essentially means, when you pass that as callback to glutReshapeFunction it breaks because

  • the types don't match
  • and there's no way to somehow pass the instance along

EDIT: C++ lambdas don't work here as pointed out by Mike Dinsdale.


Seriously, I'm really getting sick and tired of answering same question again, and again, and again, and again… It get's asked about 3 times a week.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • There seem to be a few problems with your lambda code: `graphics gr()` is a MVP, you don't capture `gr` in the lambda and most seriously I don't think a lambda with captures can be converted into a function pointer (see e.g. [here](http://stackoverflow.com/questions/10997237/c11-lambdas-to-function-pointer)) – Mike Dinsdale Sep 07 '13 at 09:22
  • @MikeDinsdale: Seems like you're right. Oh well, then back to the ffcall hacks I suggested in another answer also related to C++ member functions and callbacks: http://stackoverflow.com/a/8375672/524368 – datenwolf Sep 07 '13 at 10:29
0

it won't work this way because SizeMod is a non-static class member method, so it needs this to be called on. You have to make SizeMod static.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • It resulted me into a linking error. error LNK2019: unresolved external symbol "public: static void __cdecl graphics::SizeMod(int,int)" (?SizeMod@graphics@@SAXHH@Z) referenced in function _main –  Sep 06 '13 at 08:01
  • Put a `graphics::` before `SizeMod` in line `void SizeMod(int w, int h)` in the cpp file. – masoud Sep 06 '13 at 08:28
  • @MM. Using a static member function is not guaranteed to work, because the calling convention may differ between C++ static member functions and C functions. – datenwolf Sep 06 '13 at 10:55
  • @Annonymousisnobody: See my answer for a nice solution that uses C++11 lambdas. It also explains why those things not "just mix". – datenwolf Sep 06 '13 at 10:56
  • @datenwolf: can't you force the required convention on a static method? I think you can. – Violet Giraffe Sep 06 '13 at 11:18
  • @VioletGiraffe: No, because that is something deep down in the way the code generators work. C++ has no common ABI regarding the way, classes and class member functions look like on the binary level. With C++0x (the draft for C++11) it was actually tried to introduce such ABIs, but it never went through. So the reliable only way to do go about this is to have a wrapper outside of class scope, that's then compiled to the platform C ABI specs (which are still platform dependent, but at least every platform specifies a C ABI) and can be safely passed as a C callback. – datenwolf Sep 06 '13 at 12:02