I programmed in C# and I used the Qt framework. Both of them have their own signal slot mechanism which are really powerful. I looked at several implementations in C++ and based on what I learnt from those sources, I started to implement my own version to better understand how these could work under the hood.My implementation currently has no support for accessing the return values of the slots, and provides no thread safety. I implemented an auto disconnecting mechanism to manage the slots life cycle and disconnect them if those go out of scope. I posted the source code on GitHub. I've used std::function and variadic templates.You declare a signal this way:signal<int> test_signal; // test_signal has an int parameterYou can connect slots with the connect function:test_signal.connect(&slot_function); // void slot_function(int)// Connecting to a member function, f is the instance of the objecttest_signal.connect(&foo::slot_function, f); // void foo::slot_function(int)You can connect multiple slots to a signal which are stored in a vector. Every connect method returns a connection class which has a disconnect function which disconnects the slot from the signal. The foo object must inherit from auto_disconnect class for life cycle management. This class stores a vector of connections and when it's destructed it disconnect all of the slots. If you want to emit a signal you can use the overloaded operator().test_signal(1);I never done anything like this before and I wanted to spot any design errors, make it more efficient, and have a better understanding about this.Here is the full source code with example usage://signal.h#ifndef SIGNAL_H__#define SIGNAL_H__#include <functional>#include <vector>namespace szabi{  // When a slot is overloaded an ugly cast should be used  // static_cast<void(T::*)(<parameters>)>(&T::<slot>);  // This helper simplifies this a bit  // overload<parameters>::of(&T::slot);  template <typename... Args>  struct overload  {    template <typename F, typename R>    static constexpr auto of(R(F::*ptr)(Args...)) -> decltype(ptr)    {      return ptr;    }  };  // This class manages a connection between a signal and slot  class connection  {  public:    connection(std::function<void()>&& disconnector) : disconnector(std::move(disconnector)) {}    ~connection() {}    void disconnect() const    {      this->disconnector();    }  private:    // This will contain a lambda function which will remove the slot from the signal's vector    std::function<void()> disconnector;  };  // This class is used to disconnect all slots when the object is destroyed  class auto_disconnect  {    // A signal has access to add_connection function    template<typename... Args> friend class signal;  public:    virtual ~auto_disconnect()    {      for(const auto& conn : this->connections)      {        conn.disconnect();      }    }  protected:    void add_connection(const connection& conn)    {      this->connections.push_back(conn);    }  private:    std::vector<connection> connections;  };  template <typename... Args>  class signal  {  public:    signal() {}    virtual ~signal() {}    using slot_type = std::function<void(Args...)>;    using container_type = std::vector<slot_type>;    using iterator_type = typename container_type::iterator;    template <typename S>    connection connect(S&& slot)    {      this->slots.push_back(std::forward<S>(slot));      connection conn =      {        [&]()        {          iterator_type it = std::prev(this->slots.end());          this->slots.erase(it);        }      };      return conn;    }    template <typename S, typename T>    connection connect(S&& slot, T* instance)    {      static_assert(std::is_base_of<auto_disconnect, T>::value, T must inherit auto_disconnect);      this->slots.emplace_back([&](Args... args)      {        // Using a lambda function to call a slot which is a member function        (static_cast<T*>(instance)->*slot)(std::forward<Args>(args)...);      });      connection conn =      {        [&]()        {          iterator_type it = std::prev(this->slots.end());          this->slots.erase(it);        }      };      instance->add_connection(conn);      return conn;    }    template <typename S, typename T>    connection connect(S&& slot, T& instance)    {      static_assert(std::is_base_of<auto_disconnect, T>::value, T must inherit auto_disconnect);      return this->connect(slot, std::addressof(instance));    }    void operator()(Args const&... args)    {      for(auto const& slot : this->slots)      {        if(slot)        {          slot(args...);        }      }    }  private:    container_type slots;  };}#endif /* SIGNAL_H__ */// main.cpp#include signal.h#include <iostream>#include <cstdlib>void func(int x){  std::cout << void func( << x << ) << std::endl;}class foo : public szabi::auto_disconnect{public:  foo() {}  ~foo() {}  void func(int x)  {    std::cout << void foo::func( << x << ) << std::endl;  }  void func(int x, int y)  {    std::cout << void foo::func( << x << ,  << y << ) << std::endl;  }  void func0()  {    std::cout << void foo::func0() << std::endl;  }  void func1(int x)  {    std::cout << void foo::func1( << x << ) << std::endl;  }  void func2(int x, int y)  {    std::cout << void foo::func2( << x << ,  << y << ) << std::endl;  }};class bad : public szabi::auto_disconnect{public:  bad()  {    std::cout << bad constructed << std::endl;  }  ~bad()  {    std::cout << bad destructed << std::endl;  }  void func(int)  {    std::cout << std::endl << void bad::func() << std::endl << std::endl;  }};int main(){  szabi::signal<> signal0;  szabi::signal<int> signal1;  szabi::signal<int, int> signal2;  foo f;  signal0.connect(&foo::func0, f);  signal1.connect([](int x)  {    std::cout << Lambda func, x =  << x << std::endl;  });  signal1.connect(&func);  // overloaded slots  signal1.connect(static_cast<void(foo::*)(int)>(&foo::func), f);  signal2.connect(static_cast<void(foo::*)(int, int)>(&foo::func), f);  // using overload<...>::of(&foo::bar) helper  signal1.connect(szabi::overload<int>::of(&foo::func), f);  signal2.connect(szabi::overload<int, int>::of(&foo::func), f);  signal1.connect(&foo::func1, f);  signal2.connect(&foo::func2, f);  {    bad b;    szabi::connection conn = signal1.connect(&bad::func, b);  }  signal0();  signal1(1);  signal2(1, 2);  return EXIT_SUCCESS;}
Implementing my own signal slot mechanism using C++11
c++;c++11;event handling