![]() |
ImFusion SDK 4.3
|
Lightweight implementation of the signal-slot design pattern. More...
Lightweight implementation of the signal-slot design pattern.
Signals and slots are a variation of the Observer design pattern and used for communication between objects. This enables two classes to interact with each other without establishing a tight coupling. An observed object (subject) can notify its observers of state changes by calling a function defined by the observer.
The ImFusion SDK makes use of different interfaces for implementing the Observer pattern/event-based programming:
Use SignalImpl to define a signal. You can add any amount signals as member variables to a class. Since specifying the presence of a mutex (first template parameter) is cumbersome, it is recommended to use one of the two aliases provided: Signal for signals without mutex, ProtectedSignal for signals with a mutex. The variadic template parameter of the signal defines the number and types of the parameters passed when notifying the observers. Within the ImFusion SDK we use the convention that signals members of functions are declared public and named using signal
as prefix.
The following example class has one unprotected (no mutex) signal without payload and one protected (with mutex) signal that will cary one int and one std::string as payload when notifying its observers.
You can connect any function of matching signature to a signal. One way is to call SignalImpl::connect using a plain lambda function:
However, using plain lambdas has one significant downside/limitation: It does not provide any automatic lifetime tracking of established connections. If the observer or any object referenced in the lambda function is deleted, the signal will still have the connection and try to notify the deleted observer.
One possibility to avoid crashes in these situations is to manually keep track of the observer lifetime and remove the connection when needed using the SignalConnection object:
Since such manual lifetime management is cumbersome and error-prone, the signal-slot interface provides an automatization for this. Let the observer inherit from SignalReceiver and pass a pointer to the object when connecting to the signal. The signal-slot interface will establish an automatic bi-directional lifetime tracking: When either of the two ends of the connection is deleted the connection will be automatically removed as well.
For more details, please have a look at the documentation of SignalImpl and SignalReceiver.
Sometimes it is required to temporarily disable the emitting of a signal to avoid recursive signalling loops. The preferred solution is to use the SignalBlocker class providing a very convenient and exception-safe interface:
Alternatively, you can use the low-level functions SignalImpl::setBlocked() and SignalConnection::setBlocked() to block notifications from an entire signal or for a single connection, respectively.
Classes | |
class | DeprecatedSignal< MainSignalType, ArgTypes > |
Deprecation layer for signals. More... | |
class | SignalReceiver |
Base class for classes that can contain slots (i.e. More... | |
class | SignalConnection |
Structure for describing/identifying individual connections between signals and slots. More... | |
class | SignalImpl< UseMutex, ArgTypes > |
Implementation for a specific signal with the given signature. More... | |
class | SignalBlocker |
Convenient scope guard class to temporarily block signals/connections so that observers are not notified. More... | |
class | SignalBase |
Base interface for Signals. More... | |
Typedefs | |
template<typename... ArgTypes> | |
using | Signal = SignalImpl<false, ArgTypes...> |
Alias for a non-protected signal, which is reentrant but not thread-safe. | |
template<typename... ArgTypes> | |
using | ProtectedSignal = SignalImpl<true, ArgTypes...> |
Alias for a protected signal, which is thread-safe. | |