Signal-Slot Implementation — Part 1

C. Burak Ongay
brakulla
Published in
3 min readMay 15, 2019

As continued part of this post, this is the implementation of signal-slot mechanism in C++.

In the previous post, I tried to explain what signal-slot mechanism is. You can notify that an event is occured with some data. In using observer pattern with callbacks, you pass a function pointer but that’s not a type-safe option. So, we want to make this option as type-safe.

For now, I will just define the interface of these classes and I’ll keep doing that until I finish the requirements of these classes. This is a very effective way of designing software in my experience since this way provides revealing the design flaws as much as possible before implementing them.

Let’s create two classes as signal and slot as the first step:

We need a function on signal to notify the connected slots (I’m going to name this function `emit`), and a function to be called in slots when the event is occurred (I’m going to call this function `call`). The slot should be a function actually, and I would like to be able to use the slot with a function call syntax. I’ll implement function operator `operator()` of slot class to make it happen. But we need to pass the emitted data and we don’t know what data is going to be passed as it can be anything, and be different for each event. We can use templates:

So far so good, but what function will be called when call function is called in slot? Now this is the classical callback mechanism, we just need to give it a function to call. I want this function can be given with as a lambda and to be compatible with C++11 and later using std::function:

Here, we defined setSlotFunction to have a std::function as a parameter and we also defined the argumants of this function. So, this is type-safe. If you define a slot with int template, you cannot set its slot function taking some struct as parameter.

Now we want to be able to connect the signal to a slot. We can do that with a separate function, but I’ll make it part of signal class, for the sake of syntax (it’ll have the order of `signal connect slot`, similar to signal is connected to this slot). This function can accept a slot as parameter to which we are going to connect the signal to:

Type-safety happens here, too. When you want to connect a signal to a slot, if their template parameters does not match, the connect function of signal will not accept the slot.

We would not want these classes to be copyable, since that may lead to ambiguous connections. And for the sake of completeness, we can extend these classes:

In this version, we deleted the copy and move constructors and assignment operator. In signal, we added disconnect functions for, well, disconnecting them from connected signals. In slot, we added a overloaded constructor for giving callback function in initialization. I don’t like giving the callback function in constructor since while using slot within another class, we will have a very ugly constructor of that class. But for sake of completeness, it is there.

Now, we have our interfaces for these two classes. Let’s get to the implementation.

Since these classes are template, in order for them to be used as a library, I want to implement them as header-only classes. If we would do the implementation on a separate .cpp file and use them as library, they would not be compiled. For better explanation, please search Google with “why are template classes are header-only”.

We implemented every function we declared in these classes. Perfect! Ready to roll! If we would test it, I would run something like:

The output would be:

We received: 5

Yay!

But we are not done, yet! This is basically an observer pattern with a separated registration. We want another functionality with signal-slot mechanism, inter-thread communication. That will be the next post!

--

--