class
#include <Corrade/Interconnect/Emitter.h>
Emitter Emitter object.
Contains signals and manages connections between signals and slots. See Signals and slots for introduction.
Implementing signals
Signals are implemented as member functions with Signal as return type, argument count and types are not limited. Their body consists of a single emit() call, to which you pass pointer to the function and forward all arguments. Example signal implementations:
class Postman: public Interconnect::Emitter { public: Signal messageDelivered(const std::string& message, int price = 0) { return emit(&Postman::messageDelivered, message, price); } Signal paymentRequired(int amount) { return emit(&Postman::paymentRequired, amount); } };
The implemented signal can be emitted simply by calling the function:
Postman postman; postman.messageDelivered("hello"); postman.paymentRequired(245);
If the signal is not declared as public function, it cannot be connected or called from outside the class.
Connecting signals to slots
Signals implemented on Emitter subclasses can be connected to slots using various connect() functions. The argument count and types of slot function must be exactly the same as of the signal function. When a connection is established, returned Connection object can be used together with disconnect() to remove given connection:
Interconnect::Connection c = Interconnect::connect( postman, &Postman::paymentRequired, [](int amount) { Utility::Debug{} << "pay" << amount; }); // ... Interconnect::disconnect(postman, c);
Note that the Connection object is just a handle — its destruction doesn't lead to the connection being removed. You can also call disconnectSignal() or disconnectAllSignals() on the emitter to remove the connections. All emitter connections are automatically removed when emitter object is destroyed.
You can connect any signal, as long as the emitter object is of proper type — in particular, referring a signal from a derived type while passing an emitter of base type is not allowed:
class Base: public Interconnect::Emitter { public: Signal baseSignal() { return emit(&Base::baseSignal); } }; class Derived: public Base { public: Signal derivedSignal() { return emit(&Derived::derivedSignal); } }; Base* a = new Derived; Derived* b = new Derived; Interconnect::connect(*a, &Base::baseSignal, [](){}); // ok Interconnect::connect(*b, &Base::baseSignal, [](){}); // ok //Interconnect::connect(*a, &Derived::derivedSignal, [](){}); // error Interconnect::connect(*b, &Derived::derivedSignal, [](){}); // ok
Free function, lambda and function object slots
Slots can be simply free functions. Non-capturing lambdas, shown above, are converted to function pointers and treated the same. These have the least call overhead.
Capturing lambdas and function objects, as long as they are trivially copyable and destructible and small enough (not more than three pointers) are stored by-value similarly to free functions, but the call overhead is slightly larger.
Lambdas and function objects larger than three pointers or having non-trivial copy / destruction are allocated on heap. This is the case of std::
Member function slots
Finally, it's possible to connect signals to member functions. The receiving object must be a subclass of Receiver and slot
must be a non-constant member function with void
as a return type. In addition to the cases mentioned above, the connection is automatically removed also when receiver object is destroyed. You can also use Receiver::
class Mailbox: public Interconnect::Receiver { public: void addMessage(const std::string& message, int price) { … } }; Postman postman; Mailbox mailbox; Interconnect::connect(postman, &Postman::messageDelivered, mailbox, &Mailbox::addMessage);
You can connect to any member function, as long as Receiver exists somewhere in given object type hierarchy:
class Foo: public Interconnect::Emitter { public: Signal signal() { return emit(&Foo::signal); } }; class Base: public Interconnect::Receiver { public: void baseSlot() {} }; class Derived: public Base { public: void derivedSlot() {} }; Foo foo; Base* a = new Derived; Derived* b = new Derived; Interconnect::connect(foo, &Foo::signal, *a, &Base::baseSlot); // ok Interconnect::connect(foo, &Foo::signal, *b, &Base::baseSlot); // ok //Interconnect::connect(foo, &Foo::signal, *a, &Derived::derivedSlot); // error Interconnect::connect(foo, &Foo::signal, *b, &Derived::derivedSlot); // ok
It is also possible to connect to member function of class which itself isn't subclass of Receiver, just add Receiver using multiple inheritance. Convoluted example:
class MyString: public std::string, public Interconnect::Receiver {}; std::string c; MyString d; //Interconnect::connect(foo, &Foo::signal, c, &std::string::clear); // error Interconnect::connect(foo, &Foo::signal, d, &std::string::clear); // ok
Derived classes
-
template<std::class StateMachine
size_t states, std:: size_t inputs, class State, class Input> - State machine.
Public types
- class Signal
- Signature for signals.
Constructors, destructors, conversion operators
Public functions
- auto operator=(const Emitter&) -> Emitter& deleted
- Copying is not allowed.
- auto operator=(Emitter&&) -> Emitter& deleted
- Moving is not allowed.
- auto hasSignalConnections() const -> bool
- Whether the emitter is connected to any slot.
-
template<class Emitter, class ... Args>auto hasSignalConnections(Signal(Emitter::*)(Args...) signal) const -> bool
- Whether given signal is connected to any slot.
- auto isConnected(const Connection& connection) const -> bool
- Whether given connection still exists.
-
auto signalConnectionCount() const -> std::
size_t - Count of connections to this emitter signals.
-
template<class Emitter, class ... Args>auto signalConnectionCount(Signal(Emitter::*)(Args...) signal) const -> std::
size_t - Count of slots connected to given signal.
-
template<class Emitter, class ... Args>void disconnectSignal(Signal(Emitter::*)(Args...) signal)
- Disconnect signal.
- void disconnectAllSignals()
- Disconnect everything from this emitter signals.
Protected functions
Function documentation
bool Corrade:: Interconnect:: Emitter:: hasSignalConnections() const
Whether the emitter is connected to any slot.
template<class Emitter, class ... Args>
bool Corrade:: Interconnect:: Emitter:: hasSignalConnections(Signal(Emitter::*)(Args...) signal) const
Whether given signal is connected to any slot.
bool Corrade:: Interconnect:: Emitter:: isConnected(const Connection& connection) const
Whether given connection still exists.
Checks if the Connection object returned by connect() still refers to an existing connection. It's the user responsibility to ensure that the connection
corresponds to proper Emitter instance.
std:: size_t Corrade:: Interconnect:: Emitter:: signalConnectionCount() const
Count of connections to this emitter signals.
template<class Emitter, class ... Args>
std:: size_t Corrade:: Interconnect:: Emitter:: signalConnectionCount(Signal(Emitter::*)(Args...) signal) const
Count of slots connected to given signal.
template<class Emitter, class ... Args>
void Corrade:: Interconnect:: Emitter:: disconnectSignal(Signal(Emitter::*)(Args...) signal)
Disconnect signal.
Disconnects all slots connected to given signal. Example usage:
Postman postman; postman.disconnectSignal(&Postman::messageDelivered);
void Corrade:: Interconnect:: Emitter:: disconnectAllSignals()
Disconnect everything from this emitter signals.
template<class Emitter, class ... Args>
Signal Corrade:: Interconnect:: Emitter:: emit(Signal(Emitter::*)(Args...) signal,
typename Implementation::Identity<Args>::Type... args) protected
Emit signal.
Parameters | |
---|---|
signal | Signal |
args | Arguments |
See class documentation for more information about implementing signals.
template<class EmitterObject, class Emitter, class Functor, class ... Args>
Connection connect(EmitterObject& emitter,
Interconnect:: Emitter:: Signal(Emitter::*)(Args...) signal,
Functor&& slot)
Connect signal to function slot.
Parameters | |
---|---|
emitter | Emitter |
signal | Signal |
slot | Slot |
Connects given signal to compatible slot. emitter
must be subclass of Emitter, signal
must be implemented signal and slot
can be either a non-member function, a lambda or any other function object. The argument count and types must be exactly the same.
See Emitter class documentation for more information about connections.
Connection connect(EmitterObject& emitter,
Interconnect:: Emitter:: Signal(Emitter::*)(Args...) signal,
ReceiverObject& receiver,
void(Receiver::*)(Args...) slot)
Connect signal to member function slot.
Parameters | |
---|---|
emitter | Emitter |
signal | Signal |
receiver | Receiver |
slot | Slot |
Connects given signal to compatible slot in receiver object. emitter
must be subclass of Emitter, signal
must be implemented signal, receiver
must be subclass of Receiver and slot
must be non-constant member function with void
as return type. The argument count and types must be exactly the same.
See Emitter class documentation for more information about connections.
bool disconnect(Emitter& emitter, const Connection& connection)
Disconnect a signal/slot connection.
Parameters | |
---|---|
emitter | Emitter |
connection | Connection handle returned by connect() |
It's the user responsibility to ensure that connection
corresponds to given emitter
instance. See Emitter class documentation for more information about connections.