Signals

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.

Signal

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.

SignalConnector

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) {}
 };

SignalInterface

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.

SignalInterfaceConnector

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();
 };