Files CCore/inc/Signal.h CCore/src/Signal.cpp
A signal represents some event. Anybody interested in a reacting on the event may subscribe to receive a signal. Technically, signal is a list of subscribers. A signal assertion calls subscribers reaction methods.
The class Signal itself is very simple.
template <class ... TT>
class Signal : NoCopy
{
....
public:
// constructors
Signal();
~Signal();
// props
ulen getConnectedCount() const;
// methods
void assert(TT ... tt);
// class ConnectorBase
class ConnectorBase : NoCopy
{
....
public:
// constructors
template <class S>
explicit ConnectorBase(void (S::* call)(TT ... tt));
~ConnectorBase() {} // disconnect() must be called in the destructor of a derived class
// props
bool isConnected() const;
// methods
bool connect(Signal<TT...> &signal);
bool disconnect();
};
};
getConnectedCount() returns the number of subscribers.
assert() asserts the signal. All subscribers are called. Subscriber may disconnect itself during the call.
The inner class ConnectorBase is used to build connector classes. A connector class manages connection and disconnection to a signal.
The constructor argument call is a pointer to a method of a derived from the ConnectorBase class. This method is called when a connected signal is asserted.
isConnected() returns true, if the connector is connected to a signal.
connect() connects to a signal. The return value indicates success. Connector must be disconnected.
disconnect() disconnects a signal. The return value indicates success. Connector must be connected.
Connector can be connected only to one signal. Derived class must call disconnect() in its destructor. When a signal dies, it's automatically disconnected from all subscribers.
The class SignalConnector should be used as a connector class.
template <class S,class ... TT>
class SignalConnector : public Signal<TT...>::ConnectorBase
{
....
public:
// constructors
SignalConnector(S *obj,void (S::* method)(TT ... tt));
SignalConnector(S *obj,void (S::* method)(TT ... tt),Signal<TT...> &signal);
~SignalConnector();
};
It uses the given object and its method to react on a signal. The second constructor also connects the object to the given signal.
Normally, you should include the connector object in the subscribers class:
class Subscriber { SignalConnector<Subscriber,int> connector; private: void method(int); public: Subscriber() : connector(this,&Subscriber::method) {} };
The class SignalInterface is similar to the Signal, but provides an alternative way of the signal assertion.
template <class I>
class SignalInterface : NoCopy
{
....
public:
// constructors
SignalInterface();
~SignalInterface();
// props
ulen getConnectedCount() const;
// methods
template <class FuncInit>
void assert(FuncInit func_init); // func(I &)
// class ConnectorBase
class ConnectorBase : NoCopy
{
....
public:
// constructors
explicit ConnectorBase(I *iptr);
~ConnectorBase() {} // disconnect() must be called in the destructor of a derived class
// props
bool isConnected() const;
// methods
bool connect(SignalInterface<I> &signal);
bool disconnect();
};
};
assert() creates a functor, using Functor Init Pattern, and applies it to the interface, supplied by a subscriber. The pointer to the interface is recorded by the ConnectorBase class constructor.
The class SignalInterfaceConnector should be used as a connector class to work with the SignalInterface.
template <class I>
class SignalInterfaceConnector : public SignalInterface<I>::ConnectorBase
{
public:
// constructors
explicit SignalInterfaceConnector(I *obj);
SignalInterfaceConnector(I *obj,SignalInterface<I> &signal);
~SignalInterfaceConnector();
};