Skip to main content
Signal provides a type-safe event system for connecting callbacks (slots) to events. When a signal is emitted, all connected slots are called with the provided arguments. This is commonly used for UI event handling.

Template Parameters

template <typename... Args>
class Signal
Args
typename...
required
Types of arguments passed when the signal is emitted

Type Definitions

ConnectionID

using ConnectionID = size_t;
Unique identifier for signal connections. Used to disconnect specific callbacks.

SlotFunction

using SlotFunction = std::function<void(Args...)>;
Function type for signal slots. Must match the signal’s template parameters.

Methods

connect()

ConnectionID connect(SlotFunction slot)
Connects a callback function to the signal. The callback will be called when the signal is emitted.
slot
SlotFunction
required
Function to call when signal is emitted
return
ConnectionID
Unique ID for this connection (use for disconnect)
Signal<int, std::string> mySignal;

auto id = mySignal.connect([](int value, const std::string& text) {
    std::cout << "Received: " << value << ", " << text << std::endl;
});

emit()

void emit(Args... args) const
Emits the signal, calling all connected slots with the provided arguments.
args
Args...
required
Arguments to pass to all connected functions
mySignal.emit(42, "Hello"); // Calls all connected functions

disconnect()

void disconnect(ConnectionID id)
Disconnects a specific slot from the signal. The callback will no longer be called when the signal is emitted.
id
ConnectionID
required
ConnectionID returned from connect()
auto id = mySignal.connect(callback);
mySignal.disconnect(id);  // Remove the connection

Example Usage

Basic Signal

Signal<int, std::string> mySignal;

auto id = mySignal.connect([](int value, const std::string& text) {
    std::cout << "Received: " << value << ", " << text << std::endl;
});

mySignal.emit(42, "Hello"); // Calls the connected function
mySignal.disconnect(id);    // Remove the connection

Widget Event Handling

class Button {
public:
    Signal<> onClick;  // No arguments
    
    void handleClick() {
        onClick.emit();
    }
};

Button button;
button.onClick.connect([]() {
    std::cout << "Button clicked!" << std::endl;
});

Multiple Connections

Signal<int> valueChanged;

auto id1 = valueChanged.connect([](int value) {
    std::cout << "Handler 1: " << value << std::endl;
});

auto id2 = valueChanged.connect([](int value) {
    std::cout << "Handler 2: " << value << std::endl;
});

valueChanged.emit(100);  // Calls both handlers
valueChanged.disconnect(id1);  // Remove first handler
valueChanged.emit(200);  // Only calls second handler

Event Data

struct MouseEvent {
    int x, y;
    bool leftButton;
};

Signal<MouseEvent> onMouseClick;

onMouseClick.connect([](MouseEvent event) {
    std::cout << "Clicked at (" << event.x << ", " << event.y << ")" << std::endl;
});

onMouseClick.emit({100, 50, true});

Common Patterns

Button Click Handler

button->onClick.connect([]() {
    std::cout << "Button clicked!" << std::endl;
});

Value Changed Handler

slider->onValueChanged.connect([](float value) {
    std::cout << "New value: " << value << std::endl;
});

Text Input Handler

textInput->onTextChanged.connect([](const std::string& text) {
    std::cout << "Text changed to: " << text << std::endl;
});

Build docs developers (and LLMs) love