The observer1 design pattern is by far the most popular and widely known among behavioural patterns2. Unfortunately, unlike other mainstream languages out there, the C++ standard library doesn’t provide out of the box observer implementation. Luckily, Boost contains Signals2, a signal/slot3 library which can serve as a basis for an observer. Using Signals2 as it is, however, is not so convenient in object‐oriented program due to the need of manually coded register and notify class methods for each of signal/slot pairs. This article suggests an observable mixin4 which attempts to solve the outlined problem.
Suppose we are crafting a
Window class for a GUI application:
Window class is probably wrapping some third‐party GUI library which is irrelevant for our example. What is relevant, however, is that there exists an
Application class which wants to receive notifications whenever something happens in the
For the sake of example, let’s say that we are interested in only two events:
ShowEvent is an information only event which is fired whenever the window is shown. On the other hand, the obviously purposed
CloseEvent lets the user cancel the close operation by returning the value
false, but only if the
force_close flag is also
false (otherwise the return value is ignored by the window).
Let us define the two events mentioned along with corresponding register and notify methods with the help of Boost.Signals2 (note, in the simplest cases such as this, e.g. if there are no multiple handlers for a single event, we can use just
std::function instead of
The main issue with the above code, as you can see, is that register and notify methods need to be written manually for each of events. And a real‐world window class can easily contain dozens of them! The next section will address this issue by presenting a convenient mixin class which automatically generates the needed methods for you given the list of event handler signatures. Think of wxWidgets static event tables or MFC message maps, but without the use of macros. Or think of Qt signals and slots or Visual C++ event handling, but without the use of compiler extensions.
Implementing an Observable Mixin
The WindowObservers Class
Obviously enough, we can’t just put our signals into homogeneous container like
std::vector because of different event signatures. Fortunately, the C++ standard library provides
std::tuple, an integer‐indexed heterogeneous container which solves our needs (alternatively, we can use a tag‐indexed heterogeneous container, such as
boost::fusion::map). With the help of
std::tuple, we can define an observer table for our
Window class as shown below:
Here, we are making use of enumeration to index observers. This approach is not ideal: an insertion or removal of an observer from the tuple definition may cause a nasty bug if we are not careful enough to adjust the enumeration accordingly. The tag‐based heterogeneous containers are more immune to this issue due to the fact that the tag is mentioned explicitly as part of container element type.
The Observer Class Template
Observer type used in the above code fragment is just a simple convenience wrapper for
Aside from the signal itself, the type contains a couple of convenience type aliases and a friend declaration for the
The Observable Class Template
Observable class is what makes use of our
WindowObservers structure to generate the corresponding registration and notification methods:
Observable class maintains a table (
std::tuple in our case) of observers the definition of which is passed as class template parameter
Observers. An example of such an argument is the
WindowObervers structure defined earlier.
The class provides
Register method which is used obviously for observers registration. The function takes an arbitrary callable object (whatever Boost.Signals2 happens to support as a slot type), represented by
F&& f parameter, and an index into the tuple (
ObserverId template parameter). The function returns
boost::signals2::connection object which can be used later to unregister the observer.
The class also has
Notify method which invokes callable objects registered earlier for particular observer kind (which is given by the means of the
ObserverId template argument). The
Notify method forwards its function arguments (
args) to the callable object. The function returns the result of the last slot called, wrapped into
boost::optional (this is the default behaviour of
boost::signals2::signal; see the Boost.Signals2 documentation in case you need an advanced return semantic).
The constructor of the class is made protected because this class is not intended to be used on its own.
The Window Class
Window class now derives from
Observable class template parametrised by
WindowsObservers. This give us a possibility to use
Notify methods on
The Application Class
Finally, the application class registers the callbacks for
Putting It All Together
Here is a self‐sufficient test program which puts together the above code snippets:
In this article we have seen how modern C++ features, in particular, variadic templates and perfect forwarding allow us to implement a generic variant of observer pattern without the use of either macros or proprietary compiler extensions.
I have also experimented with alternative implementations, namely, the one based on
boost::fusion::map instead of
std::tuple and the other which uses
std::function instead of
boost::signals2::signal. You can find them in a gist.
A software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. The observer pattern is also a key part in the model–view–controller (MVC) architectural pattern. ↩
Used to manage relationships, interaction, algorithms and responsibilities between objects. The behavioural pattern focuses on the interaction between the cooperating objects in a manner that the objects are communicating while maintaining loose coupling. ↩
A language construct for communication between objects which makes it easy to implement the Observer pattern while avoiding boilerplate code. For example, GUI widgets can send signals containing event information which can be received by other controls using special functions known as slots. ↩
A class that acts as the parent class, containing the desired functionality. A subclass can then inherit or simply reuse this functionality, but without creating a rigid, single ‘is a’ relationship (Wikipedia). ↩
In the UML a type of static structure diagram that describes the structure of a system by showing the system’s classes, their attributes, operations (or methods), and the relationships among objects (Wikipedia). ↩