2

I'd like to wrap (Facade Pattern) Allegro's use of threads i.e. install_int_ex(void (__cdecl*)(void), int tick); and remove_int(void (__cdecl*)(void)) with a class I wrote that uses templates and user-defined Functor Objects to install interrupts and remove interrupts when the class is created and destroyed.

I keep getting compiler errors: error C2664: 'install_int_ex' : cannot convert parameter 1 from 'void (__thiscall [User-defined FunctorName Here]::* )(void)' to 'void (__cdecl *)(void)' and similar for remove_int(void (__cdecl*)(void))

This seems to work provided the called function accepts pointers to void*user data

Unfortunately, Allegro is not this flexible. Is there a way around this limitation or am I going to have to use Windows's CreateThread (and learn threading "the real way" in the process)?

See Also: Using a C++ Member Function as the Thread's Entry-Point-Function

Community
  • 1
  • 1
Casey
  • 10,297
  • 11
  • 59
  • 88
  • You can't pass non-static member functions as c style functions. Try making the function static. – cppguy Jun 21 '12 at 00:49
  • @cppguy: That's just it, I can't. It's a FunctorObject passed in by the user. I have no control over it. – Casey Jun 21 '12 at 00:54
  • What about `std::bind` (c++11) or `boost::bind` ( – nikolas Jun 21 '12 at 00:59
  • @nijansen: I'm using VS2010. Will switch to 2011 when it's out of beta and has released its first Service Pack. – Casey Jun 21 '12 at 01:01
  • So `std::bind` is not and option, but what about `boost::bind`? – nikolas Jun 21 '12 at 01:13
  • @nijansen: Boost is forever broken in my mind. When I tried to use it (recently) it failed to compile with errors in Boost's own code. – Casey Jun 21 '12 at 17:25

2 Answers2

4

This is not really possible. This is the function type that is expected (ignore __cdecl):

void (*)(void);

It doesn't take any parameters. If this were a non-static member function in C++, there would be an implicit this parameter, but this is C. If you want to pass a parameter to your function (including the implicit this parameter), you can't do it this way.

You can either use a global variable to pass the functor (bad), or just use threads instead.

However,

Please note the allegro documentation for install_int_ex (source):

You should be aware, however, that it will be called in an interrupt context, which imposes a lot of restrictions on what you can do in it. It should not use large amounts of stack, it must not make any calls to the operating system, use C library functions, or contain any floating point code, and it must execute very quickly.

An interrupt context is a dangerous thing, it is not the same thing as threading and you should NOT put C++ code in an interrupt context unless you are very good at figuring out what your C++ code does.

DO NOT PASS A C++ FUNCTION TO install_int_ex. (Again, unless you know exactly what library calls your C++ code is or is not making.)

In general, it is more difficult to learn how to program code that runs in interrupts than it is to learn how to write multithreaded code. Interrupts wreak havoc with library functions in ways that threads don't, and there are a number of security holes and bugs in well-known programs caused by subtle mistakes in signal handlers.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • If I could upvote this a million times, I would. I hope you'll settle for one vote and an accept. :) – Casey Jun 21 '12 at 01:59
0

You're passing a non-static member function of the class AlarmFunctionObject. Try declaring the member function as static. If you need to access an actual AlarmFunctionObject, you'll have to pass a static function that calls your non-static member function in it on some object you have access to at that scope

class AlarmFunctionObject
{
public:
    static void func()
    {
        someInstanceOfAlarmFunctionObject->myMemberAFunc();
    }
    void myMmberFunc()
    {
        // do stuff
    }
};

and pass AlarmFunctionObject::func instead of myMemberFunc

cppguy
  • 3,611
  • 2
  • 21
  • 36