I'm working with a different team on a project. The other team is constructing a GUI, which, like most GUI frameworks is very inheritance driven. On the other hand, the code on this side ('bottom end', I guess one could say) is essentially C (though I believe it's all technically C++ via the MSVC2010 toolchain w/o the "treat as C" flag.
Both modules (UI and this) must be compiled separately and then linked together.
Problem:
A need has popped up for the bottom end to call a redraw function on the GUI side with some data given to it. Now here is where things go bad. How can you call INTO a set of member functions, especially one w/ complex dependencies? If I try to include the window header, there's an inheritance list for the GUI stuff a mile long, the bottom end obviously isn't build against the complex GUI libs...I can't forward declare my way out because I need to call a function on the window?
Now obviously this is a major communication design flaw, though we're in a bad position right now where major restructuring isn't really an option.
Questions:
How SHOULD have this been organized for the bottom end to contact the top for a redraw, going from a ball of C like code to a ball of C++ node.
What can I do now to circumvent this issue?
The only good way I can think of is with some sort of communication class...but I don't see how that won't run into the same issue as it will need to be built against both the GUI and the bottom end?
If you only need to call a single function, or even a small subset of functions, a callback is probably your best bet. If you're dealing with a member function, you can still call it with a pointer to the member function and a pointer to the object in question. See this answer for details on doing that. However, this could mean requiring that you include the entire mile-long list of dependencies for the GUI code.
Edit: After some thought, you could do a callback for a few functions without needing to include the dependencies for the GUI code. For example:
In the GUI code somewhere...
int DoFooInBar(int arg1, const char *arg2){
return MyForm.ChildContainer.ChildBox.ChildButton.Bar.DoFoo( arg1, arg2 );
}
Now in GUICallbacks.hpp...
int DoFooInBar(int arg1, const char *arg2);
You could then include GUICallbacks.hpp and call DoFooInBar() from anywhere in your C code. The only issue with this method is that you would need to make a new function for every callback you want to use.
A more general method of accomplishing such a task in bulk is via passing messages. A very cross-platform method for doing this involves a communication object, as you have mentioned. You wouldn't necessarily encounter any build issues if you provide a mechanism for obtaining a pointer to a shared communication object by a naming mechanism. A small example would be:
class CommObj{
public:
struct Message{
uint32_t type;
uint32_t flags;
std::string title;
std::string contents;
... //maybe a union here or something instead
};
private:
static map<std::string, CommObj*> InternalObjects;
std::deque<Message> Messages;
std::string MyName;
public:
CommObj(const char *name); //Registers the object in the map
~CommObj(); //Unregisters the object in the map
void PushMessage( uint32_t type, uint32_t flags, const char *title, const char *contents, ...);
Message GetMessage();
bool HasMessages();
static CommObj *GetObjByName(const char *name);
static bool ObjWithNameExists();
};
Obviously you can make a more C-like version, however this is in C++ for clarity. The implementation details are an exercise for the reader.
With this code, you may then simply build both the backend and frontend against this object, and you can run a check on both sides of the code to see if a CommObj with the name "Backend->GUI" has been made yet. If not, make it. You would then be able to start communicating with this object by grabbing a pointer to it with GetObjByName("Backend->GUI"); You would then continuously poll the object to see if there are any new messages. You can have another object for the GUI to post messages to the backend too, perhaps named "GUI->Backend", or you could build bi-directionality into the object itself.
An alternative method would be to use socket communication / shared file descriptors. You could then read and write data to the socket for the other side to pick up. For basic signalling, this may be a simple way to accomplish what you need, especially if you don't really need anything complex. A simple send() call to a socket descriptor would be all you need to signal the other side of the code.
Do be aware that using sockets could cause slowdowns if used incredibly heavily. It depends on the underlying implementation, but sockets on localhost are often slower than raw function calls. You probably aren't going to need interlocked signalling in a tight loop though, so you should be fine with either method. When I say slower, I mean it's maybe 50 microseconds vs 5 microseconds. It's not really anything to worry too much about for most situations, but something to be aware of. On the flipside, if the GUI code is running in a different thread from the backend code, you would likely want to mutex the communications object before posting/reading messages, which wouldn't be needed with a shared file descriptor. Mutexes/semaphors bring their own baggage along to deal with.
Using a communications object like the one I gave an outline for would allow for some automatic marshaling of types, which you might be interested in. Granted, you could also write an object to do that marshaling with a socket too, however at that point you might as well use a shared object.
I hope your project ends up going smoothly.
Related
I am trying to make an architecture for a MMO game and I can't figure out how I can store as many variables as I need in GameObjects without having a lot of calls to send them on a wire at the same time I update them.
What I have now is:
Game::ChangePosition(Vector3 newPos) {
gameobject.ChangePosition(newPos);
SendOnWireNEWPOSITION(gameobject.id, newPos);
}
It makes the code rubbish, hard to maintain, understand, extend. So think of a Champion example:
I would have to make a lot of functions for each variable. And this is just the generalisation for this Champion, I might have have 1-2 other member variable for each Champion type/"class".
It would be perfect if I would be able to have OnPropertyChange from .NET or something similar. The architecture I am trying to guess would work nicely is if I had something similar to:
For HP: when I update it, automatically call SendFloatOnWire("HP", hp);
For Position: when I update it, automatically call SendVector3OnWire("Position", Position)
For Name: when I update it, automatically call SendSOnWire("Name", Name);
What are exactly SendFloatOnWire, SendVector3OnWire, SendSOnWire ? Functions that serialize those types in a char buffer.
OR METHOD 2 (Preffered), but might be expensive
Update Hp, Position normally and then every Network Thread tick scan all GameObject instances on the server for the changed variables and send those.
How would that be implemented on a high scale game server and what are my options? Any useful book for such cases?
Would macros turn out to be useful? I think I was explosed to some source code of something similar and I think it used macros.
Thank you in advance.
EDIT: I think I've found a solution, but I don't know how robust it actually is. I am going to have a go at it and see where I stand afterwards. https://developer.valvesoftware.com/wiki/Networking_Entities
On method 1:
Such an approach could be relatively "easy" to implement using a maps, that are accessed via getters/setters. The general idea would be something like:
class GameCharacter {
map<string, int> myints;
// same for doubles, floats, strings
public:
GameCharacter() {
myints["HP"]=100;
myints["FP"]=50;
}
int getInt(string fld) { return myints[fld]; };
void setInt(string fld, int val) { myints[fld]=val; sendIntOnWire(fld,val); }
};
Online demo
If you prefer to keep the properties in your class, you'd go for a map to pointers or member pointers instead of values. At construction you'd then initialize the map with the relevant pointers. If you decide to change the member variable you should however always go via the setter.
You could even go further and abstract your Champion by making it just a collection of properties and behaviors, that would be accessed via the map. This component architecture is exposed by Mike McShaffry in Game Coding Complete (a must read book for any game developer). There's a community site for the book with some source code to download. You may have a look at the actor.h and actor.cpp file. Nevertheless, I really recommend to read the full explanations in the book.
The advantage of componentization is that you could embed your network forwarding logic in the base class of all properties: this could simplify your code by an order of magnitude.
On method 2:
I think the base idea is perfectly suitable, except that a complete analysis (or worse, transmission) of all objects would be an overkill.
A nice alternative would be have a marker that is set when a change is done and is reset when the change is transmitted. If you transmit marked objects (and perhaps only marked properties of those), you would minimize workload of your synchronization thread, and reduce network overhead by pooling transmission of several changes affecting the same object.
Overall conclusion I arrived at: Having another call after I update the position, is not that bad. It is a line of code longer, but it is better for different motives:
It is explicit. You know exactly what's happening.
You don't slow down the code by making all kinds of hacks to get it working.
You don't use extra memory.
Methods I've tried:
Having maps for each type, as suggest by #Christophe. The major drawback of it was that it wasn't error prone. You could've had HP and Hp declared in the same map and it could've added another layer of problems and frustrations, such as declaring maps for each type and then preceding every variable with the mapname.
Using something SIMILAR to valve's engine: It created a separate class for each networking variable you wanted. Then, it used a template to wrap up the basic types you declared (int, float, bool) and also extended operators for that template. It used way too much memory and extra calls for basic functionality.
Using a data mapper that added pointers for each variable in the constructor, and then sent them with an offset. I left the project prematurely when I realised the code started to be confusing and hard to maintain.
Using a struct that is sent every time something changes, manually. This is easily done by using protobuf. Extending structs is also easy.
Every tick, generate a new struct with the data for the classes and send it. This keeps very important stuff always up to date, but eats a lot of bandwidth.
Use reflection with help from boost. It wasn't a great solution.
After all, I went with using a mix of 4, and 5. And now I am implementing it in my game. One huge advantage of protobuf is the capability of generating structs from a .proto file, while also offering serialisation for the struct for you. It is blazingly fast.
For those special named variables that appear in subclasses, I have another struct made. Alternatively, with help from protobuf I could have an array of properties that are as simple as: ENUM_KEY_BYTE VALUE. Where ENUM_KEY_BYTE is just a byte that references a enum to properties such as IS_FLYING, IS_UP, IS_POISONED, and VALUE is a string.
The most important thing I've learned from this is to have as much serialization as possible. It is better to use more CPU on both ends than to have more Input&Output.
If anyone has any questions, comment and I will do my best helping you out.
ioanb7
I'm working on a piece of software that is constructed from a series of "modules". Modules can be connected together to form the full application (one module might go to another, sort of an implied state machine). Each module can render to the screen, get updates and access state from other modules. Note that the modules are still within the same process, so no IPC needs to be designed into this.
However, these modules do not directly depend on each other. There is a singleton object that has the sole purpose of managing message passing between the modules. When you want to register for an event from any module:
CPostMaster::Instance().RegisterEvent("TheEventName", [](std::string const& data) { /* the callback */ });
The data variable is serialized data. Can be anything, but usually is XML or JSON. To send the event you do:
std::string serialized_data = /* serialized data, do this before calling */;
CPostMaster::Instance().SendEvent("TheEventName", serialized_data);
The 2nd parameter is optional.
Having a "master authority" for message passing has a drawback: The events themselves can't send varying parameters without utilizing some sort of serialization or type erasure (removes type safety from the picture and impacts performance).
But it also has the benefit of strict/strong coupling not being required, which means that at any given time a different module can be responsible for sending a specific event without the receiving modules having to change.
The alternative seems to be not using a singleton, and instead each module receives an object that it can use to subscribe to. This could get messy especially when you are passing them around everywhere, it will quickly mean that functions start taking boilerplate parameters.
What is a good design for message passing in a system such as this? How can it be improved and be made manageable? Type safety and open/close principles are important here. I think it's OK to have direct dependencies across modules so long as they can be mocked (for unit testing) and easily swapped out should modules change without severely impacting the whole system (but this is part of the open/close principle).
First: I dislike singletons. The only singleton I accept is a singleton manager (some sort of central instance distributor) that handles a defined init and deinit of all "singletons" in a defined order.
But back to your problem:
Your title already has the solution: Define a message interface. If you want type-safety define an IMessage with common attributes.
Then define specializations of IMessage which then are consumed by your callbacks.
The tricky part is: You will need RTTI for that, which is odd in c++, I know but might be worth the benefits, if you are restricted to gcc or visual studio, you could make use of those types, or implement some simple RTTI in the IMessage itself to avoid dynamic_cast.
To avoid boilerplate code in a callback which checks and casts around the IMessage I would provide a utility function (pseudo code, adjust for pointers, references, smart ptrs, const correctness etc.)
T SafeCast<T>(IMessage message);
depending on the implementation of your compiler you should add restrictions to T to be of a sub type of IMessage and what should happen when the cast fails (exception, nullptr, etc).
Alternatively: Check how others have solved this (maybe Qt's Signals&Slots or something in Boost)
I would make the sub modules dependent on a parent class (in your case the singleton). Then you could pass this object's reference along the line, to be used in the modules.
Module(Handler& h) : _h(h) { }
void do_stuff(){
_h.RegisterEvent("TheEventName", [](std::string const& data)
{ /* the callback */ })
Then I would register your Module class itself, or another class, as an Event, and on the Handler side, I would formalize the messaging in a way that you'd get multiple callbacks instead of just one. You'd have to formalize your message though, but you'd have type safety instead of passing strings.
For example the handler, while parsing a message, he'd call:
_callback.start(); //signals the start of a message
_callback.signalParam1(1); //calls Module.signalParam(int);
_callback.signalParam2("test"); //calls Module.signalParam2(const char*);
_callback.end();
Your Module would need to implement those.
When dealing with microcontrollers there are things that are inherently global - I'm thinking about peripherals like serial ports or other interfaces. There are also peripherals that are not only global but there is only one (and there will never be more) - like peripheral controlling core clocks or interrupt controller. These peripherals do have some kind of global state (for example - core clock is set to something) and it's inefficient to reverse-calculate these values.
If I'd like my program to be nicely object-oriented, I'm having hard time deciding how to deal with such objects... Global variables are not nice and this is obvious, but I just don't know (not enough experience) whether I should try to "hide" the fact that these things ARE global... For example "cin" or "stdout" are globals too (let's ignore the fact that in multithreaded apps these are usually thread-specific) and noone is hiding that... Let's stick with the clock generator peripheral - there is only one, so I could use the singleton anti-pattern (; or make the class static or just have the single object global (that's what I have usually done), as this object has the current clock setting stored and this value is needed for LOTS of other things - it's needed to set system timer used by RTOS, it's needed to set clocks for other peripherals (UART baudrate, SPI bitrate, ...), it's needed to set correct clock for external memories or configure memory wait states. That's why I think that creating one object in main() and passing it around everywhere would be a bit cumbersome...
I could write the methods so that all "global" information would come from the peripheral registers (for example the core frequency could be reverse-calculated from current PLL settings), but this also seems like a wrong idea, not to mention that creating object for clock generator peripheral everywhere would look funny...
Current clock setting could be stored in static member of the class, but from here there's only one small step towards a fully static class (as "this" pointer will be useless for a class that has no state)...
The solution usually found in not-object-oriented programs is closest to fully static class - there are only functions that operate on global variables.
Anyone has some nice idea how to deal with such scenario nicely or whether this problem is worth the time? Maybe I should just use one global object and be done with it? (;
If I'd like my program to be nicely object-oriented, I'm having hard time deciding how to deal with such objects... Global variables are not nice and this is obvious, but I just don't know (not enough experience) whether I should try to "hide" the fact that these things ARE global...
When I read that, I wonder if you know why you are using OOP and why you don't use globals.
Firstly, OOP is a tool, not a goal. In your case, the interrupt controller doesn't need things like derivation and virtual functions. All you will need is an interface to program it, wrapped in a single class. You could even use a set of plain functions that do that (C=style modular programming) without giving up on maintainability. In your case, making the single instance global is even clearer. Imagine the alternative, where different parts of the program could instantiate a class that is used to access the same UART underneath. If you're using globals, the code (or rather the author) is aware of this and will think about how to coordinate access.
Now, concerning the globals, here's an example why not to use them:
int a, b, c;
void f1()
{
c = a;
f3();
}
void f2()
{
c = b;
f3();
}
void f3()
{
// use c
}
int main()
{
a = 4;
f1();
b = 5;
f2();
}
The point here is that parameters are stored in globals instead of passing them around as actual parameters and making it difficult to see where and when they are used. Also, the use above totally rules out any recursive calls. Concerning your environment, there are things that are inherently global though, because they are unique parts of the environment, like the interrupt controller (similar to cin/cout/cerr/clog). Don't worry about those. There have to be really many of them used all over the place until you need to think about restricting access.
There are two guidelines to make this easier:
The larger the scope of an object, the more it needs a speaking name (compare to a, b, c above). In your case, I'd store all hardware-specific objects in a common namespace, so it is obvious that some code is accessing globals. This also allows separate testing and reuse of this namespace. Many hardware vendors even provide something like this in the form of a library, in order to help application development.
In the code wrapping/modelling the hardware, perform requests but don't make decisions that are specific to the application on top of it. Compare to e.g. the standard streams, that are provided but never used by the standard library itself, except maybe for dumping fatal error information before aborting after a failed assertion.
You have pretty much outlined your options:
globals
static data members of classes / singletons
It's ultimately up to you to decide between the two, and choose which you like more from the aesthetic or other prospective.
At the end of the day, just as you have said, you'll still have one clock generator, one UART, etc.
One thing to keep in mind is that too much abstraction solely for the purpose of abstraction isn't going to buy you much if anything. What it may do, however, is make it harder for someone unfamiliar to your code figure out how things really work behind the layers of classes. So, take into account your team, if any.
The Singleton pattern is a source of debate, for sure. Some people simply say it's "bad", but I would disagree; it is just widely misused and misunderstood. It is definitely useful in certain situations. In fact, it applies to exactly the situation you've described.
If you have a class that needs to be available globally and by its very nature cannot have multiple instances, then a singleton is the best option.
Singletons, global objects, static classes, they are all the same. Dress the evil global state in whatever sauce you want, it's still global state. The problem is in the salad, not in the dressing, so to speak.
A little-explored path is monadic code, Haskell-style (yes in C++). I have never tried it myself, but from the looks of it, this option should be fun. See e.g. here for an example implementation of Monad interface in C++.
I'm looking for a solution for this problem in C or C++.
edit: To clarify. This is on a linux system. Linux-specific solutions are absolutely fine. Cross-plaform is not a concern.
I have a service that runs in its own thread. This service is a class with several methods, some of which need to run in the own service's thread rather than in the caller's thread.
Currently I'm using wrapper methods that create a structure with input and output parameters, insert the structure on a queue and either return (if a "command" is asynchronous) or wait for its execution (if a "command" is synchronous).
On the thread side, the service wakes, pops a structure from the queue, figures out what to execute and calls the appropriate method.
This implementation works but adding new methods is quite cumbersome: define wrapper, structure with parameters, and handler. I was wondering if there is a more straightforward means of coding this kind of model: a class method that executes on the class's own thread, instead of in the caller's thread.
edit - kind of conclusion:
It seems that there's no de facto way to implement what I asked that doesn't involve extra coding effort.
I'll stick with what I came up with, it ensures type safeness, minimizes locking, allows sync and async calls and the overhead it fairly modest.
On the other hand it requires a bit of extra coding and the dispatch mechanism may become bloated as the number of methods increases. Registering the dispatch methods on construction, or having the wrappers do that work seem to solve the issue, remove a bit of overhead and also remove some code.
My standard reference for this problem is here.
Implementing a Thread-Safe Queue using Condition Variables
As #John noted, this uses Boost.Thread.
I'd be careful about the synchronous case you described here. It's easy to get perf problems if the producer (the sending thread) waits for a result from the consumer (the service thread). What happens if you get 1000 async calls, filling up the queue with a backlog, followed by a sync call from each of your producer threads? Your system will 'play dead' until the queue backlog clears, freeing up those sync callers. Try to decouple them using async only, if you can.
There are several ways to achieve this, depending upon the complexity you want to accept. Complexity of the code is directly proportional to the flexibility desired. Here's a simple one (and quite well used):
Define a classes corresponding to each functionality your server exposes.
Each of these classes implements a function called execute and take a basic structure called input args and output args.
Inside the service register these methods classes at the time of initialization.
Once a request comes to the thread, it will have only two args, Input and Ouput, Which are the base classes for more specialized arguments, required by different method classes.
Then you write you service class as mere delegation which takes the incoming request and passes on to the respective method class based on ID or the name of the method (used during initial registration).
I hope it make sense, a very good example of this approach is in the XmlRpc++ (a c++ implementation of XmlRpc, you can get the source code from sourceforge).
To recap:
struct Input {
virtual ~Input () = 0;
};
struct Ouput {
virtual ~Output () = 0;
};
struct MethodInterface {
virtual int32_t execute (Input* __input, Output* __output) = 0;
};
// Write specialized method classes and taking specialized input, output classes
class MyService {
void registerMethod (std::string __method_name, MethodInterface* __method);
//external i/f
int32_t execute (std::string __method, Input* __input, Output* __output);
};
You will still be using the queue mechanism, but you won't need any wrappers.
IMHO, If you want to decouple method execution and thread context, you should use Active Object Pattern (AOP)
However, you need to use ACE Framework, which supports many OSes, e.g. Windows, Linux, VxWorks
You can find detailed information here
Also, AOP is a combination of Command, Proxy and Observer Patterns, if you know the details of them, you may implement your own AOP. Hope it helps
In addition to using Boost.Thread, I would look at boost::function and boost::bind. That said, it seems fair to have untyped (void) arguments passed to the target methods, and let those methods cast to the correct type (a typical idiom for languages like C#).
Hey now Rajivji, I think you have it upside-down. Complexity of code is inversely proportional to flexibility. The more complex your data structures and algorithms are, the more restrictions you are placing on acceptable inputs and behaviour.
To the OP: your description seems perfectly general and the only solution, although there are different encodings of it. The simplest may be to derive a class from:
struct Xqt { virtual void xqt(){} virtual ~Xqt(){} };
and then have a thread-safe queue of pointers to Xqt. The service thread then just pops the queue to px and calls px->xqt(), and then delete px. The most important derived class is this one:
struct Dxqt : Xqt {
xqt *delegate;
Dxqt(xqt *d) : delegate(d) {}
void xqt() { delegate->xqt(); }
};
because "all problems in Computer Science can be solved by one more level of indirection" and in particular this class doesn't delete the delegate. This is much better than using a flag, for example, to determine if the closure object should be deleted by the server thread.
I am entering a realm that is new to me, but basically I need to implement callbacks in C++. I am designing a toolkit for myself to use to simplify my life. Basically it is a .dll plugin that will be exposing a lot of functions to my other .dll plugins.
One of these functions is HookEvent(const char *event_name, void *callback) which will allow me to hook different events that get fired. Here would be an example...
Example_Plugin1.dll does HookEvent("player_spawn", &Plugin1::Event_PlayerSpawn);
Example_Plugin2.dll does HookEvent("player_spawn", &Plugin2::Event_PlayerSpawn);
I need to figure out the best (and preferably easiest) method of setting up a callbacks system that will work well for this. I have been reading up on C++ callbacks for a few hours now, and found quite a few different approaches.
I assume the easiest thing to do would be make a template, and use typedef bool (ClassName::*EventHookCallback)(IGameEvent, bool); After that, I am a bit foggy.
I also read that Delegates or a .NET style events system are other possible approaches. I am already somewhat confused, so I don't want to confuse myself more, but figured it was worth asking.
Here is a link to the C++ .NET style events system I was reading about.
http://cratonica.wordpress.com/2010/02/19/implementing-c-net-events-in-c/
So what do you guys suggest? Any tips as far as implementing it would be most appreciated.
If you want generalized event firing Boost.Signals2 might be applicable.
The Boost.Signals2 library is an
implementation of a managed signals
and slots system. Signals represent
callbacks with multiple targets, and
are also called publishers or events
in similar systems. Signals are
connected to some set of slots, which
are callback receivers (also called
event targets or subscribers), which
are called when the signal is
"emitted."
Even if you don't need this level of flexibility you should be able to simplify the function binding in your code using Boost.Bind, or the C++0x equivalents.
EDIT:
There's an excellent discussion from Herb Sutter of the issues you could face here. You could use this for guidance if you decide you don't need the full Boost feature set, and so roll your own.
How about using Qt Signal and Slot? It does what callbacks do but without the messiness of making anything not part of your callback parameters global.
Boost.Signals would be my choice, combined with things like boost::bind and Boost.Function.
I would use an abstract base class as a plugin interface. (And in fact, I have used a pattern like the one below before.)
Library, PluginIfc.h:
class PluginIfc {
public:
virtual ~PluginIfc() = 0;
virtual bool EventCallback(const char* event_name, IGameEvent, bool) = 0;
};
// For Windows, add dllexport/dllimport magic to this declaration.
// This is the only symbol you will look up from the plugin and invoke.
extern "C" PluginIfc* GetPlugin();
Plugin:
#include <PluginIfc.h>
class Plugin1 : public PluginIfc {
public:
virtual bool EventCallback(const char* event_name, IGameEvent, bool);
Plugin1& get() { return the_plugin_obj; }
bool Event_PlayerSpawn(IGameEvent, bool);
// ...
private:
std::vector<std::string> _some_member;
static Plugin1 the_plugin_obj; // constructed when plugin loaded
};
Plugin1 Plugin1::the_plugin_obj;
PluginIfc* GetPlugin() { return &Plugin1::get(); }
This way, your plugin classes can easily have members, and C++'s virtual call mechanism takes care of giving you a good this pointer in EventCallback.
It may be tempting to make a virtual method per event type, say just make Event_PlayerSpawn and similar methods virtual. But then whenever you want to add an event type, if this means changing class PluginIfc, your old compiled plugins are no longer compatible. So it's safer to use a string event identifier (for extensibility) and have the main callback sort events off to more specific methods.
The major drawback here (as compared to a signal-slot type implementation) is that all callbacks must take the same set of arguments. But your question sounded like that would be adequate. And it's often possible to work within that limitation by making sure the set of arguments is very flexible, using strings to be parsed or Any-style objects.
Sounds like you might be interested in how to build your own plugin framework. The problems you'll encounter are likely the same. Have a look at this nice Dr Dobbs article Building Your Own Plugin Framework.
Hope this helps!
Implementing your own callback system is non-trivial.
My understanding is that your aim is to map event types to specific callback functions.
E.g. if "player_spawn" event is risen the &Plugin1::Event_PlayerSpawn will be called.
So what you should do is the following:
1) Define all the events of interest. Make them as generic as possible. They can
encapsulate any information you need
2) Create a Registrar. I.e. a class that all modules register their interest for specific
methods. E.g. Registrar.register(player_spawn,this,Event_PlayerSpawn);
3) Registrar has a queue of all subscribers.
4) You can also have a uniform interface for the modules. I.e. all module implement a specific function but based on event's data can do different things
5) When an event occurs, all the subscribers interested for the specific event get notified by calling the appropriate function
6)Subscriber can de-register when ever is need
Hope this helps.