I’m searching a way to avoid systematic dynamic cast in the following problem.
I have Action objects and Message objects. Action objects have methods that emits messages, and other methods that accept messages. There are of course derived Action classes and Messages classes. The objects and their methods are connected dynamically at run time by string identification based on a configuration file defining the network of interconnected objects.
This is equivalent to a signal slot system with a strong constrain on the number and type of the arguments. All signals emit a message derived of the class Message and all slots accept a message derived from the class Message.
Connections are NxN. Thus signals are multicast and slots can accept signals from multiple sources.
The current implementation is to use a Link class instantiating the connection between a signal and a slot. The signals and slots are functor member variables. Each Action object has a two maps. One from string name to signal and one from string name to slot. There is also a global map of Action names to instance. The benefit of keeping track of links in the target Action (slots) is to properly disconnect all links when the instance is destroyed.
In a first pass all Action instances defined in the configuration file are instantiated, In a second pass links are instantiated connecting signals to slots.
The question is how would you implement this so that a message type matching check is only performed when the link is instantiated and so that a dynamic cast is only performed if required.
For instance if we have the message base class M and a subclass M1 of M and a subclass M2 of M1, a link from signal(M2) to slot(M1) or slot(M) would not perform a dynamic cast, and a link from signal(M1) or signal(M) to slot(M2) would perform a dynamic cast. The slot method is only called is the dynamic cast succeeds (doesn’t return nullptr).
An implementation where a dynamic cast is performed at each call is trivial. I seek a solution to avoid this if possible.
My current understanding is that I can’t use boost::signals because of the dynamic binding.
I’ve solved my problem. Here is the code which is nicely concise.
The signal is also a template class which simply defines the message types it may emit.
Thus, when connecting the signal with a slot, the Link constructor can check the polymorphic compatibility of the message type emitted by the signal and the message type accepted by the slot. It then copies the appropriate function pointer whether a dynamic cast is required or not. What is not shown here is the Type class and how it is used to check message type compatibility.
The answer was how to define the two slot functions and their function pointers.
Here is an example how the slots would be defined in a class:
Here is the Slot and SlotT classes definition.