Examples » Signals and slots

Easy-to-use API to connect listeners to events.

Signal and slots are a technique introduced in Qt, which allows to intuitively pass events to arbitrary objects and methods without unnecessary boilerplate code (such as various EventListener interfaces in Java).

Basically there is an emitter with special functions called signals. Each signal function can have an arbitrary number of parameters. The signals are connected to slots, which can be either free functions, member functions or lambdas with the same argument list. When the emitter emits signal, all slots connected to it are called and signal arguments are passed to them.

The signal/slot connection is automatically removed when either emitter or (when the signal is connected to member function) receiver object is destroyed. The connection can be removed also explicitly — you can remove one particular connection, all connections to given slot or all connections to given object.

Implementing signals

Signals are implemented in some Interconnect::Emitter subclass as public functions with Signal as return type. There are no limitations on argument types or argument count. The signal function calls emit() internally, passes its own signature and all arguments to it and propagates the returned value.

class RemoteControl: public Interconnect::Emitter {
        Signal triggered(const std::string& password, int timeout) {
            return emit(&RemoteControl::triggered, password, timeout);

Implementing slots

Any free function, lambda function or non-constant member function returning void can be connected to any signal if both have the same argument count and types. If connecting to a member function, you have to derive your class from Interconnect::Receiver to ensure that the connection is automatically removed when receiver is destroyed.

class Bomb: public Interconnect::Receiver {
        void launch(const std::string& password, int timeout);

void Bomb::launch(const std::string& password, int timeout) {
    if(password != "terrorist69") {
        Utility::Error{} << "Wrong password. No apocalypse will be performed.";

    Utility::Warning{} << "Launching bomb in" << timeout << "seconds.";

    // ...

    delete this; // commit suicide

Connecting signals to slots

Once you have instances of emitter and receiver objects, you can connect signals from emitters to slots. There are no connectivity limitations, you can connect any number of signals to one slot and any number of slots to one signal. See Interconnect::connect() for more information about how to manage the connections.

int main() {
    RemoteControl rc;
    Bomb *bomb1 = new Bomb,
         *bomb2 = new Bomb,
         *bomb3 = new Bomb;

    Interconnect::connect(rc, &RemoteControl::triggered, *bomb1, &Bomb::launch);
    Interconnect::connect(rc, &RemoteControl::triggered, *bomb2, &Bomb::launch);
    Interconnect::connect(rc, &RemoteControl::triggered, *bomb3, &Bomb::launch);

    Utility::Debug{} << "Successfully installed" << rc.signalConnectionCount()
                     << "bombs.";

See Interconnect::disconnect(), Interconnect::Emitter::disconnectSignal(), Interconnect::Emitter::disconnectAllSignals() and Interconnect::Receiver::disconnectAllSlots() functions for information about removing connections.

Emitting signals

The implemented signal can be emitted simply by calling the function.

    rc.triggered("terrorist69", 60); // Launch all connected bombs after 60 seconds

        Utility::Fatal{1} << "Mission failed!" << rc.signalConnectionCount()
                          << "bombs didn't explode!";

    Utility::Debug{} << "Mission succeeded!";

Compiling and running the example

After a successful compilation the application will print out this text:

$ ./interconnect
Successfully installed 3 bombs.
Launching bomb in 60 seconds.
Launching bomb in 60 seconds.
Launching bomb in 60 seconds.
Mission succeeded!

See the whole example below. The example is also in the GitHub repository.