I put up some code on github that implements basic signals and slots functionality using standards compliant C++. It’s one header file “signals.hpp”. See here: link to github
This implementation of signals is a re-work of some code by a user _pi on the forums for the cross-platform application framework Juce — that thread is here — which was itself a re-work of some example code posted by Aardvajk in the GameDev.net forums (here). I just put it all together, cleaned things up, fixed some bugs, and added lambda support.
The basic idea is that given variadic templates being added to C++ it became possible for a more straight-forward implementation of signal and slot functionality beyond what was done for boost::signals et. al. — that is what Aardvajk’s original article was about. _pi changed Aardvajk’s code to make it such that slots are a thing you inherit from, which makes more sense to me. I changed _pi’s code so that it uses std::functions to store the handlers thus allowing lambdas with captures to be attached to a signal.
Usage is like the following:
#include "signals.hpp" #include <iostream> // a handler is a kind of slot, that, as an implementation detail, requires usage of the // "curiously recurring template pattern". That is, the intention is for instances of // a class C that will react to a signal firing to have an is-a relationship with a slot // parametrized on class C itself. class CharacterHandler : public Slot<CharacterHandler> { public: void HandleCharacter(char c) { std::cout << "The user entered '" << c << "'" << std::endl; } }; class DigitHandler : public Slot<DigitHandler> { public: void HandleCharacter(char c) { if (c >= '0' && c <= '9') { int n = static_cast<int>(c - '0'); std::cout << " " << n << " * " << n << " = " << n*n << std::endl; } } }; int main() { bool done = false; char c; Signal<char> signal; CharacterHandler character_handler; DigitHandler digit_handler; // can attach a signal to a slot with matching arguments signal.connect(character_handler, &CharacterHandler::HandleCharacter); // can also attach a lambda, associated with a slot. // (the lambda could capture the slot and use it like anything else it captures // however technically all the associated slot is doing is allowing you to have // a way of disconnecting the lambda e.g. in this case signal.disconnect(characterHandler) signal.connect(character_handler, [&](char c) -> void { if (c == 'q') done = true; } ); // can also attach a slot to a signal ... this means the same as the above. digit_handler.connect(signal, &DigitHandler::HandleCharacter); do { std::cin >> c; signal.fire(c); } while (! done); // can disconnect like this character_handler.disconnect(signal); // or this signal.disconnect(digit_handler); //although disconnecting wasnt necessary here in that just gaving everything go out of scope // wouldve done the right thing. return 0; }