You.i Engine
CYISignal< SignalTypes > Class Template Reference

Detailed Description

template<typename... SignalTypes>
class CYISignal< SignalTypes >

Signals and slots are a thread-safe and flexible communication framework that will allow various objects to transfer data synchronously or asynchronously in a highly decoupled manner. The classes that are using signals and slots do not need to share any interfaces to each other of each other. Signals and slots are also highly resilient against short lived objects: if a slot is deleted, the connection will detach automatically even while a CYISignal::Emit() is in progress, in which the deletion of the slot will be delayed.

Warning
Signals and slots should not be used in time-critical sections, as they heavily make use of mutexes for thread-safety. Synchronous signals can be four times slower than calling a virtual function directly.

Here is an example of how to use the CYISignal and CYISignalHandler to mark a class:

// first we add a signal into this class
class SomeClass
{
// a one parameter signal named "MySignal"
};
// Secondly, make our slots
class MyHandler : public CYISignalHandler
{
public:
void DoSomething();
void DoSomethingElse(uint32_t data);
};
// The last step is to instantiate our signal and slot and wire them up
void Setup()
{
SomeClass *pSomeClass = new SomeClass();
MyHandler *pMyHandler = new MyHandler();
// Connect. Notice how a connection is established between
// SomeClass and MyHandler while not even knowing anything
// about each other.
pSomeClass->MySignal.Connect(*pMyHandler, &MyHandler::DoSomething);
pSomeClass->MySignal.Connect(*pMyHandler, &MyHandler::DoSomethingElse);
// And we emit a signal. Both MyHandler::DoSomething and
// MyHandler::DoSomethingElse should be called, while MyHandler::DoSomethingElse
// receives the value of 42.
pSomeClass->MySignal(42);
// if we delete the handler, the connection is automatically disconnected.
delete pMyHandler;
// this won't have any effect, and most importantly, it won't crash
pSomeClass->MySignal(43);
// finally, delete SomeClass. Memory leaks are bad.
delete pSomeClass;
}

Connecting to a signal

As a general rule, signals can be connected to any Callable slot, as defined by the C++ standard. The following is a partial list of the types that signals can be connected to:

  • Raw functions
  • Raw member functions
  • std::function objects
  • Member functions through std::function objects
  • std::bind'ed functions through std::function objects
  • std::bind'ed member functions through std::function objects
  • Lambdas
  • Any object that implements operator() publicly

The following code example shows how to connect to different slot types.

// Create our slots
static void FreeFunction();
static void AnotherFreeFunction(float floatData, uint32_t unsignedData);
class MyHandler : public CYISignalHandler
{
public:
void DoSomething();
void DoSomethingElse(uint32_t data);
};
// The last step is to instantiate our signal and slot and wire them up
void Setup()
{
MyHandler myHandler;
// Connect to a 'raw' static function
MySignal.Connect(&FreeFunction);
// Connect to a 'raw' member function
MySignal.Connect(myHandler, &MyHandler::DoSomething);
// Connect to an std::function object
std::function<void()> freeFunction = &FreeFunction;
MySignal.Connect(freeFunction);
// Connect to a member function through an std::function object
std::function<void(MyHandler &)> memberFunction = std::mem_fn(&MyHandler::DoSomething);
MySignal.Connect(myHandler, memberFunction);
// Connect to a bind'ed function
std::function<void(uint32_t)> bindFunction = std::bind(&AnotherFreeFunction, 2.5f, std::placeholders::_1);
MySignal.Connect(bindFunction);
// Connect to a bind'ed member function
std::function<void(MyHandler &)> bindMemberFunction = std::bind(&MyHandler::DoSomethingElse, std::placeholders::_1, 42);
MySignal.Connect(myHandler, bindMemberFunction);
// Connect to a lambda
MySignal.Connect([](uint32_t data) { std::cout << data; });
// Connect to a lambda with handler capture
MySignal.Connect(myHandler, [&](uint32_t data) { myHandler.DoSomethingElse(data); });
}

Connection types

Connect() functions takes as last input an optional connection type. By default, the connection type is EYIConnectionType::Auto. Automatic connection means that when CYISignal::Emit() is called, the CYISignal will look at the slot's thread affinity to determine if it should call it directly (synchronously), or if it should be queued on the slot's thread (asynchronously) if a CYIEventDispatcher is running on that given thread. The slot affinity is determined by the thread that instantiated the CYISignalHandler. Please note that the CYISignalHandler can also be moved to a different thread after instantiation using CYISignalHandler::MoveToThread. For connections without a signal handler, the thread affinity can be passed as an argument and, by default, is the thread that established the connection. You can also force the connection to be always synchronous by setting the connection type to EYIConnectionType::Sync. In this case, it will always call the slot using the CYISignal's current context, but it is your responsibility to assure thread-safety in your slot's implementation. You can also force the connection to always be asynchronous by setting the connection type to EYIConnectionType::Async. This connection type will always queue the CYISignal onto the CYIEventDispatcher of the context in which the CYISignalHandler resides. If there are no event dispatcher running on the given context, the application event dispatcher will be used.

It is highly recommended to leave the connection type as EYIConnectionType::Auto unless the other connection types are absolutely necessary. In the automatic mode, the context switching will automatically occur only when it is necessary, and is completely transparent to the user.

Here is an code example on how to make signals asynchronous using a CYIEventDispatcherThread. In this example, the connection type is EYIConnectionType::Auto but the effective connection type is EYIConnectionType::Async because of the different thread affinity.

// first we add a signal into this class
class SomeClass
{
public:
// a one parameter signal named "MySignal"
};
// Secondly, make our slots
class MyHandler : public CYISignalHandler
{
public:
void DoSomething();
void DoSomethingElse(uint32_t data);
};
// And then make a thread class
class MyThread : public CYIEventDispatcherThread
{
public:
MyThread();
MyHandler *GetHandler();
protected:
virtual void Run() override;
private:
MyHandler *m_pHandler;
};
inline MyThread::MyThread()
: m_pHandler(NULL)
{
}
inline MyHandler *MyThread::GetHandler()
{
return m_pHandler;
}
inline void MyThread::Run()
{
// the Handler will be bound to this new thread.
m_pHandler = new MyHandler();
// start the event dispatcher by running default Run()
// This will block until someone calls CYIEventDispatcherThread::Terminate()
delete m_pHandler;
m_pHandler = NULL;
}
// The last step is to instantiate our signal and slot and wire them up
void Setup()
{
MyThread *pThread = new MyThread();
pThread->StartThread();
SomeClass *pSomeClass = new SomeClass();
// Connect. Notice how a connection is established between
// SomeClass and MyHandler while not even knowing anything
// about each other.
pSomeClass->MySignal.Connect(*(pThread->GetHandler()), &MyHandler::DoSomething);
pSomeClass->MySignal.Connect(*(pThread->GetHandler()), &MyHandler::DoSomethingElse);
// And we emit a signal. Both MyHandler::DoSomething and
// MyHandler::DoSomethingElse should be called, while MyHandler::DoSomethingElse
// receives the value of 42. The only difference from the 1st example is that the
// signal will be queued and will return immediately. Signal is automatically asynchronous.
pSomeClass->MySignal(42);
YI_SLEEP(100); // wait for thread to process the signal event
delete pThread; // Will call Terminate() on your behalf
// this won't have any effect, and most importantly, it won't crash
pSomeClass->MySignal(43);
// finally, delete SomeClass. Memory leaks are bad.
delete pSomeClass;
}

Checking for existing connections

The IsConnected functions can be used to detect if a signal is connected to a given slot. The function CYISignalBase::IsConnected(const CYISignalConnectionID &) function can be used for any slot type, but the IsConnected functions that take as input slots can only be used with raw function slots.

Note
If a connection is made to a 'raw' function using an std::function as intermediary, the IsConnected(SLOT) functions cannot be used to check if a connection exists. The CYISignalBase::IsConnected(const CYISignalConnectionID &) function must be used instead.

The following gives an example of how to check for existing connections;

// first we add a signal into this class
class SomeClass
{
public:
// a one parameter signal named "MySignal"
};
// Secondly, make our slots
class MyHandler : public CYISignalHandler
{
public:
void DoSomething();
void DoSomethingElse(uint32_t data);
};
// The last step is to instantiate our signal and slot and wire them up
void Setup()
{
SomeClass someClass;
MyHandler myHandler;
// No connections currently exist, so both of these would return 'false'.
someClass.MySignal.IsConnected(myHandler, &MyHandler::DoSomething); // will return 'false'
someClass.MySignal.IsConnected(myHandler, &MyHandler::DoSomethingElse); // will return 'false'
// Connect.
CYISignalConnectionID id = someClass.MySignal.Connect(myHandler, &MyHandler::DoSomething);
// Now connections exist
someClass.MySignal.IsConnected(myHandler, &MyHandler::DoSomething); // will return 'true'
someClass.MySignal.IsConnected(myHandler, &MyHandler::DoSomethingElse); // will return 'false'
// The connection ID can also be used to check if a connection exists
someClass.MySignal.IsConnected(id); // will return 'true'
}

Disconnecting signals and slots

Signals and Slots are both threadsafe and deletion safe. This means that if a handler object is deleted while it is connected to a signal, the connections between the signal and the handler object are automatically severed in a thread-safe manner. Similarly, deleting a signal automatically disconnects that signal from any currently-connected handler object in a thread-safe manner.

In some cases, it is desirable to manually disconnect a slot from its associated signal.

For 'raw' function connections, this can be done using the Disconnect() functions (passing in the function pointer to the slot, as well as the signal handler if necessary).

For all other slot connections (such as connections to lambdas or to std::function objects), the CYISignalConnectionID object must be used. This object is returned when the connection is established, and must be retained by the user.

Here is an example of how connections can be disconnected:

// First we add a signal into this class
class SomeClass
{
public:
// A one parameter signal named "MySignal"
};
// Secondly, make our slots
class MyHandler : public CYISignalHandler
{
public:
void DoSomething();
void DoSomethingElse(uint32_t data);
void DoSomethingElseEntirely();
};
// Now, the last step is to instantiate our signal and slot and wire them up.
void Setup()
{
SomeClass someClass;
MyHandler myHandler;
// Connect to a few slots.
someClass.MySignal.Connect(myHandler, &MyHandler::DoSomething);
CYISignalConnectionID id = someClass.MySignal.Connect(myHandler, &MyHandler::DoSomethingElse);
someClass.MySignal.Connect(myHandler, &MyHandler::DoSomethingElseEntirely);
// Disconnect using the slot itself
someClass.MySignal.Disconnect(myHandler, &MyHandler::DoSomething);
// Disconnect using a connection ID
someClass.MySignal.Disconnect(id);
// Disconnect the signal from the handler
someClass.MySignal.Disconnect(myHandler);
}

Copying signals

When a signal is copied, all of its slot connections are copied as well. This should be kept in mind when copying objects that have signal members.

Similarily, copying a signal handler also copies all of its signal connections.

Note
When a signal is copied, the copy uses the same CYISignalConnectionID objects to identify its connections. This allows users of the copy to use previously-stored connection ID objects.
Warning
If an object is copied that contains signals connected to the object itself, it is necessary to disconnect the copied signal and the copied object, and reconnect manually. If this is not done, the copied signal would be connected to the original object, and the copied object would be connected to the original signal.

Connecting to std::function slots

std::function objects can be connected to from signal objects. As with 'raw' function pointers, connections to std::function objects can be made even if the std::function objects takes less parameters as input than the signal emits. Parameters of std::function objects only need to be convertible to the types of the signal – an exact match is not necessary.

Unlike connections to 'raw' slots, connections to std::function objects can only be disconnected by hanging onto the CYISignalConnectionID object that is returned at connection time. This is because std::function cannot be compared for equality.

Warning
The same std::function object can be connected to multiple times.

Three different Connect types exist for std::function objects:

  • Connect with signal handler and the signal handler is a parameter of the std::function
  • Connect with signal handler but the std::function does not have the handler as a parameter
  • Connect with std::function only

When using one of the first two Connect types, the signal connection is automatically disconnected when the signal handler is deleted. With the third Connect type, the signal connection is disconnected only when the signal itself is deleted (or when the user manually disconnects from the signal using a CYISignalConnectionID object).

Warning
When assigning a callable to an std::function object, care must be made to properly match the parameter types and the return types. Some compilers allow the return type to be void even if the callable does not return void, but this is undefined behaviour and does not work on other compilers (namely the Visual Studio compiler).
Some compilers require that std::mem_fn be used when assigning member functions to std::function objects (namely the Visual Studio compiler).

Connecting lambdas, std::bind'ed functions, and generic Callable objects

Lambdas, functors and std::bind'ed functions can all be connected to through an std::function object. With the exception of std::bind'ed functions, connections can be established directly without using an intermediate std::function object. The same limitations exist for lambdas and std::bind'ed functions as for std::function: the same slot can be connected to multiple times, and disconnection can only be done using the CYISignalConnectionID.

Note
To be able to connect to objects that implement operator(), those objects must be copyable.
Warning
When using a lambda with a by-reference capture (and, to some extent, when using an std::bind'ed function with an object pointer or reference), care must be taken to ensure that the connection does not outlive the capture. This can be mitigated by using shared pointers, or by passing a reference to a signal handler in the Connect call. Using the [&] capture type is not recommended.

Follows is an example of how to 'safely' capture 'this' in a lambda:

// First we add a signal into this class
class SomeClass
{
public:
// A one parameter signal named "MySignal"
};
// Secondly, make our slots
class MyHandler : public CYISignalHandler
{
public:
void DoSomething(int i);
void Setup(SomeClass &myClass)
{
// The following lambda captures 'this' by reference, and all other variables by copy
int value = 42;
auto lambda = [=]() { DoSomething(value); };
// The following Connect call would be unsafe: if MyHandler was deleted, MySignal would still have a
// connection to the lambda, which would be holding a dangling reference to MyHandler through its capture
//myClass.MySignal.Connect(lambda);
// The following Connect call is safe: if MyLambda is deleted, the provided CYISignalHandler reference
// would disconnect the lambda from the signal
myClass.MySignal.Connect(*this, lambda);
}
};
// Now, setup the handler and emit the signal
void Run()
{
SomeClass myClass;
MyHandler myHandler;
myHandler.Setup(myClass);
myClass.MySignal(43u);
}

Disconnecting or Connecting during Emit

Disconnecting a slot from a signal while that signal is being emitted is supported. If the slot being disconnected has not been called yet, calling it will be skipped. Disconnecting the slot that is currently being called is also supported. However, deleting the object containing the slot that is currently being called is not supported.

Connecting to a signal while that signal is being emitted is supported. However be aware that the newly-connected slot will be called after the connection has been established (and before the signal's emit function call completes).

See also
CYISignalHandler
CYIEventDispatcherThread

#include <signal/YiSignal.h>

Inheritance diagram for CYISignal< SignalTypes >:

Public Member Functions

template<typename HandlerType , typename SlotReturnType , typename... SlotTypes>
bool IsConnected (const HandlerType &rSignalHandler, SlotReturnType(HandlerType::*const pSlot)(SlotTypes...)) const
 
template<typename HandlerType , typename SlotReturnType , typename... SlotTypes>
bool IsConnected (const HandlerType &rSignalHandler, SlotReturnType(HandlerType::*const pSlot)(SlotTypes...) const) const
 
template<typename SlotReturnType , typename... SlotTypes>
bool IsConnected (SlotReturnType(*const pSlot)(SlotTypes...)) const
 
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID Connect (HandlerType &rSignalHandler, SlotReturnType(SlotHandlerType::*const pSlot)(SlotTypes...), EYIConnectionType type=EYIConnectionType::Auto)
 
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID Connect (const HandlerType &rSignalHandler, SlotReturnType(SlotHandlerType::*const pSlot)(SlotTypes...) const, EYIConnectionType type=EYIConnectionType::Auto)
 
template<typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID Connect (SlotReturnType(*const pSlot)(SlotTypes...), EYIConnectionType type=EYIConnectionType::Auto, CYIThreadHandle threadAffinity=CYIThread::GetCurrentThreadId())
 
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID Connect (HandlerType &rSignalHandler, std::function< SlotReturnType(SlotHandlerType &, SlotTypes...)> slot, EYIConnectionType type=EYIConnectionType::Auto)
 
template<typename CallableType >
CYISignalConnectionID Connect (CallableType &&callable, EYIConnectionType type=EYIConnectionType::Auto, CYIThreadHandle threadAffinity=CYIThread::GetCurrentThreadId())
 
template<typename CallableType >
CYISignalConnectionID Connect (const CYISignalHandler &rSignalHandler, CallableType callable, EYIConnectionType type=EYIConnectionType::Auto)
 
template<typename... OtherSignalTypes>
CYISignalConnectionID Connect (CYISignal< OtherSignalTypes... > &slotSignal, EYIConnectionType type=EYIConnectionType::Auto)
 
void operator() (const typename std::decay< SignalTypes >::type &... param) const
 
void Emit (const typename std::decay< SignalTypes >::type &... params) const
 
template<class SlotReturnType , typename SlotHandlerType , typename... SlotTypes>
void Disconnect (CYISignalHandler &rSignalHandler, SlotReturnType(SlotHandlerType::*const pSlot)(SlotTypes...))
 
template<class SlotReturnType , typename SlotHandlerType , typename... SlotTypes>
void Disconnect (CYISignalHandler &rSignalHandler, SlotReturnType(SlotHandlerType::*const pSlot)(SlotTypes...) const)
 
template<typename SlotReturnType , typename... SlotTypes>
void Disconnect (SlotReturnType(*const pSlot)(SlotTypes...))
 
- Public Member Functions inherited from CYISignalBase
virtual bool IsConnected () const override
 
virtual bool IsConnected (const CYISignalBase &rSignal) const override
 
bool IsConnected (const CYISignalHandler &rSignalHandler) const
 
bool IsConnected (CYISignalConnectionID connectionID) const
 
void Disconnect (CYISignalHandler &rSignalHandler)
 
void Disconnect (CYISignalConnectionID connectionID)
 
void Disconnect (CYISignalBase &rSignal)
 
- Public Member Functions inherited from CYISignalHandler
 CYISignalHandler ()
 
 CYISignalHandler (const CYISignalHandler &rSignalHandler)
 
virtual ~CYISignalHandler ()
 
CYISignalHandleroperator= (const CYISignalHandler &rSignalHandler)
 
void MoveToThread (CYIThread *pThread)
 This function allows the user to override the default thread affinity to any CYIThread that may or may not be running. More...
 
CYIThreadHandle GetThreadAffinity () const
 
void SetThreadAffinity (const CYIThreadHandle &rThreadAffinity)
 
void Disconnect (CYISignalBase &rSignal)
 
void DisconnectFromAllSignals ()
 
- Public Member Functions inherited from CYIThread::Listener
 Listener ()
 
virtual ~Listener ()
 
virtual void OnThreadStarted (CYIThread *)
 
virtual void OnThreadTerminated (CYIThread *)
 
virtual void OnThreadFinished (CYIThread *)
 

Protected Member Functions

void EmitForConnection (CYISignalConnectionWrapper &connection, const CYIThreadHandle &currentThreadID, EYIConnectionType connectionType, const typename std::decay< SignalTypes >::type &... params)
 
virtual void Emitted ()
 
virtual void ConnectionAdded (CYISignalConnectionWrapper &connection)
 
- Protected Member Functions inherited from CYISignalBase
 CYISignalBase ()
 
 CYISignalBase (const CYISignalBase &rSignal)
 
virtual ~CYISignalBase ()
 
CYISignalBaseoperator= (const CYISignalBase &rSignal)
 
void RemoveConnection (CYISignalHandler &rSignalHandler, NotifyFlag notifyHandler)
 
void RemoveAllConnections (NotifyFlag notifyHandler)
 
void RegisterToSignalHandler (const CYISignalHandler &rSignalHandler)
 
void UnregisterFromSignalHandler (CYISignalHandler &rSignalHandler)
 
void ExclusiveLock (CYIRecursiveSpinLock &signalMutex) const
 
void ExclusiveLock (const CYISignalHandler &rSignalHandler, CYIRecursiveSpinLock &signalMutex) const
 
void ExclusiveUnlock (CYIRecursiveSpinLock &signalMutex) const
 
void ExclusiveUnlock (const CYISignalHandler &rSignalHandler, CYIRecursiveSpinLock &rSignalMutex) const
 
bool HasConnection (const CYISignalHandler &rSignalHandler) const
 
void CloneConnectionAndConnectTo (CYISignalBase &signal, const CYISignalConnectionWrapper &connection)
 

Additional Inherited Members

- Protected Attributes inherited from CYISignalBase
CYILazy< SignalObjectsm_signalObjects
 

Member Function Documentation

◆ Connect() [1/7]

template<typename... SignalTypes>
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( HandlerType &  rSignalHandler,
SlotReturnType(SlotHandlerType::*)(SlotTypes...)  pSlot,
EYIConnectionType  type = EYIConnectionType::Auto 
)

Establish a connection between this CYISignal and the member function slot pSlot using the signal handler rSignalHandler.

Connections are unique when established using this function. Calling this function a second time using the same slot has no effect.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

If the CYISignalHandler goes out-of-scope or is deleted, the connection will be automatically destroyed. You do not need to manually call CYISignal::Disconnect when deleting any instance of a subclass of CYISignalHandler.

Warning
The rSignalHandler parameter must be a subclass of CYISignalHandler, and the slot must be a public member of that CYISignalHandler subclass.
Note
This function is thread-safe.

◆ Connect() [2/7]

template<typename... SignalTypes>
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( const HandlerType &  rSignalHandler,
SlotReturnType(SlotHandlerType::*)(SlotTypes...) const  pSlot,
EYIConnectionType  type = EYIConnectionType::Auto 
)
inline

Establish a connection between this CYISignal and the const member function slot pSlot using the const signal handler rSignalHandler.

Connections are unique when established using this function. Calling this function a second time using the same slot has no effect.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

If the CYISignalHandler goes out-of-scope or is deleted, the connection will be automatically destroyed. You do not need to manually call CYISignal::Disconnect when deleting any instance of a subclass of CYISignalHandler.

Warning
The rSignalHandler parameter must be a subclass of CYISignalHandler, and the slot must be a public member of that CYISignalHandler subclass.
Note
Connecting to a non-const slot using a const signal handler is not permitted.
This function is thread-safe.

◆ Connect() [3/7]

template<typename... SignalTypes>
template<typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( SlotReturnType(*)(SlotTypes...)  pSlot,
EYIConnectionType  type = EYIConnectionType::Auto,
CYIThreadHandle  threadAffinity = CYIThread::GetCurrentThreadId() 
)

Establish a connection between this CYISignal and the static function slot pSlot.

Connections are unique when established using this function. Calling this function a second time using the same slot has no effect.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

By default, the thread affinity of the connection is that of the thread from which the connection is established.

Note
This function is thread-safe.

◆ Connect() [4/7]

template<typename... SignalTypes>
template<typename HandlerType , typename SlotHandlerType , typename SlotReturnType , typename... SlotTypes>
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( HandlerType &  rSignalHandler,
std::function< SlotReturnType(SlotHandlerType &, SlotTypes...)>  slot,
EYIConnectionType  type = EYIConnectionType::Auto 
)

Establish a connection between this CYISignal and the std::function slot slot using the signal handler rSignalHandler. Connecting to const member functions is also supported so long as a const signal handler is provided.

Because std::function objects cannot be compared, the same std::function can be connected to multiple times. To disconnect an std::function connection, the CYISignalConnectionID object returned by this function must be used.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

If the CYISignalHandler goes out-of-scope or is deleted, the connection will be automatically destroyed. You do not need to manually call CYISignal::Disconnect when deleting any instance of a subclass of CYISignalHandler.

Warning
The rSignalHandler parameter must be a subclass of CYISignalHandler, and the slot must refer to a public member of that CYISignalHandler subclass.
Note
This function is thread-safe.
See also
CYISignalBase::IsConnected(CYISignalConnectionID) const
CYISignalBase::Disconnect(CYISignalConnectionID)

◆ Connect() [5/7]

template<typename... SignalTypes>
template<typename CallableType >
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( CallableType &&  callable,
EYIConnectionType  type = EYIConnectionType::Auto,
CYIThreadHandle  threadAffinity = CYIThread::GetCurrentThreadId() 
)

Establish a connection between this CYISignal and the Callable slot slot. This is typically used to connect to lambda functions.

Because Callable objects cannot be compared, the same Callable can be connected to multiple times. To disconnect a Callable connection, the CYISignalConnectionID object returned by this function must be used.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

By default, the thread affinity of the connection is that of the thread from which the connection is established.

Note
This function is thread-safe.
See also
CYISignalBase::IsConnected(CYISignalConnectionID) const
CYISignalBase::Disconnect(CYISignalConnectionID)

◆ Connect() [6/7]

template<typename... SignalTypes>
template<typename CallableType >
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( const CYISignalHandler rSignalHandler,
CallableType  callable,
EYIConnectionType  type = EYIConnectionType::Auto 
)

Establish a connection between this CYISignal and the Callable slot slot, tying the lifetime of the connection to the lifetime of the rSignalHandler.

Because Callable objects cannot be compared, the same Callable can be connected to multiple times. To disconnect a Callable connection, the CYISignalConnectionID object returned by this function must be used.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

If the CYISignalHandler goes out-of-scope or is deleted, the connection will be automatically destroyed. You do not need to manually call CYISignal::Disconnect when deleting any instance of a subclass of CYISignalHandler.

Note
The rSignalHandler parameter is not passed to pSlot when the signal is emitted. The signal handler is used only to bind the lifetime of the connection to that of rSignalHandler.
This function is thread-safe.
See also
CYISignalBase::IsConnected(CYISignalConnectionID) const
CYISignalBase::Disconnect(CYISignalConnectionID)

◆ Connect() [7/7]

template<typename... SignalTypes>
template<typename... OtherSignalTypes>
CYISignalConnectionID CYISignal< SignalTypes >::Connect ( CYISignal< OtherSignalTypes... > &  slotSignal,
EYIConnectionType  type = EYIConnectionType::Auto 
)

Establish a daisy-chain connection between this CYISignal and the slot signal slotSignal.

Connections are unique when established using this function. Calling this function a second time using the same slot has no effect.

Note that you can always connect a CYISignal to slots that have fewer parameters than the signal, but not the other way around. When the CYISignal is emitted, the unused parameters will simply be ignored. The parameters of the slot must be convertible to from the signal parameter types. The slot may have any return type. Reference and pointer parameters are allowed.

If the slot signal goes out-of-scope, or is deleted in the event that it was allocated on the heap, the connection will be automatically destroyed. You do not need to manually call CYISignal::Disconnect when deleting any instance of CYISignal.

Note
This function is thread-safe.

◆ ConnectionAdded()

template<typename... SignalTypes>
virtual void CYISignal< SignalTypes >::ConnectionAdded ( CYISignalConnectionWrapper connection)
protectedvirtual

A handler called when a connection added to this signal object.

Note
The signal mutex (and signal handler mutex, if applicable) is locked when this function is called.

◆ Disconnect() [1/3]

template<typename... SignalTypes>
template<class SlotReturnType , typename SlotHandlerType , typename... SlotTypes>
void CYISignal< SignalTypes >::Disconnect ( CYISignalHandler rSignalHandler,
SlotReturnType(SlotHandlerType::*)(SlotTypes...)  pSlot 
)

Destroy a signal/slot connection between this signal and the member function pSlot (using the signal handler rSignalHandler).

Once this function has been called, calling CYISignal::Emit() will not result in the disconnected slot receiving the signal, unless the emit is asynchronous and it has already been queued to the CYIEventDispatcher.

Note
If a connection doesn't exists with a given slot, calling the function has no effect.
This function is thread-safe.
See also
CYISignalBase::Disconnect(CYISignalHandler &)

◆ Disconnect() [2/3]

template<typename... SignalTypes>
template<class SlotReturnType , typename SlotHandlerType , typename... SlotTypes>
void CYISignal< SignalTypes >::Disconnect ( CYISignalHandler rSignalHandler,
SlotReturnType(SlotHandlerType::*)(SlotTypes...) const  pSlot 
)
inline

Destroy a signal/slot connection between this signal and the const member function pSlot (using the const signal handler rSignalHandler).

Once this function has been called, calling CYISignal::Emit() will not result in the disconnected slot receiving the signal, unless the emit is asynchronous and it has already been queued to the CYIEventDispatcher.

Note
If a connection doesn't exists with a given slot, calling the function has no effect.
This function is thread-safe.
See also
CYISignalBase::Disconnect(CYISignalHandler &)

◆ Disconnect() [3/3]

template<typename... SignalTypes>
template<typename SlotReturnType , typename... SlotTypes>
void CYISignal< SignalTypes >::Disconnect ( SlotReturnType(*)(SlotTypes...)  pSlot)

Destroy a signal/slot connection between this signal and the static function pSlot.

Once this function has been called, calling CYISignal::Emit() will not result in the disconnected slot receiving the signal, unless the emit is asynchronous and it has already been queued to the CYIEventDispatcher.

Note
If a connection doesn't exists with a given slot, calling the function has no effect.
This function is thread-safe.

◆ Emit()

template<typename... SignalTypes>
void CYISignal< SignalTypes >::Emit ( const typename std::decay< SignalTypes >::type &...  params) const
inline

Emits the CYISignal with the given parameters params.

Calling this function in turn calls all slots connected to this signal.

Note
The parameter values are copied only if an async connection exists or if a connection is made to a slot that takes in parameters by value.
This function is thread-safe.

◆ EmitForConnection()

template<typename... SignalTypes>
void CYISignal< SignalTypes >::EmitForConnection ( CYISignalConnectionWrapper connection,
const CYIThreadHandle currentThreadID,
EYIConnectionType  connectionType,
const typename std::decay< SignalTypes >::type &...  params 
)
protected

Emits for connection pConnection with the given parameters params.

Note
The parameter values are copied only if an async connection exists or if a connection is made to a slot that takes in parameters by value.

◆ Emitted()

template<typename... SignalTypes>
virtual void CYISignal< SignalTypes >::Emitted ( )
protectedvirtual

A handler called after a signal has been emitted.

Note
This handler is not called if the signal's 'signal objects' does not exist (which typically happens when the signal has no connection.)
The signal mutex (and signal handler mutex, if applicable) is locked when this function is called.

◆ IsConnected() [1/3]

template<typename... SignalTypes>
template<typename HandlerType , typename SlotReturnType , typename... SlotTypes>
bool CYISignal< SignalTypes >::IsConnected ( const HandlerType &  rSignalHandler,
SlotReturnType(HandlerType::*)(SlotTypes...)  pSlot 
) const

Checks if a connection has been established between this CYISignal and the slot pSlot.

Note
This function is thread-safe.
See also
CYISignalBase::IsConnected() const
CYISignalBase::IsConnected(const CYISignalBase &rSignal) const
CYISignalBase::IsConnected(const CYISignalHandler &rSignalHandler) const

◆ IsConnected() [2/3]

template<typename... SignalTypes>
template<typename HandlerType , typename SlotReturnType , typename... SlotTypes>
bool CYISignal< SignalTypes >::IsConnected ( const HandlerType &  rSignalHandler,
SlotReturnType(HandlerType::*)(SlotTypes...) const  pSlot 
) const
inline

Checks if a connection has been established between this CYISignal and the const slot pSlot.

Note
This function is thread-safe.
See also
CYISignalBase::IsConnected() const
CYISignalBase::IsConnected(const CYISignalBase &rSignal) const
CYISignalBase::IsConnected(const CYISignalHandler &rSignalHandler) const

◆ IsConnected() [3/3]

template<typename... SignalTypes>
template<typename SlotReturnType , typename... SlotTypes>
bool CYISignal< SignalTypes >::IsConnected ( SlotReturnType(*)(SlotTypes...)  pSlot) const

Checks if a connection has been established between this CYISignal and the static function slot pSlot.

Note
This function is thread-safe.
See also
CYISignalBase::IsConnected() const
CYISignalBase::IsConnected(const CYISignalBase &rSignal) const

◆ operator()()

template<typename... SignalTypes>
void CYISignal< SignalTypes >::operator() ( const typename std::decay< SignalTypes >::type &...  param) const
inline

Emits the CYISignal with the given parameters params.

This function make it possible to use the Signal as a 'functor'. Calling this function in turn calls all slots connected to this signal.

Note
The parameter values are copied only if an async connection exists or if a connection is made to a slot that takes in parameters by value.
This function is thread-safe.

The documentation for this class was generated from the following file: