Search code examples
c++classsignals-slots

Advanced class features and C++ standard libraries, some questions about example


Im having trouble to understand some advanced feature of c++. Im trying to code my own signals/slots system,found exaple and run into some questions:

  • Signal() : current_id_(0) {} - is it some sort of derived class ? what does 0 means here ?
  • int connect_member(T *inst, void (T::*func)(Args...)) { - what does "T::" do here ?
  • mutable std::map<int, std::function<void(Args...)>> slots_; - whats happenning when "slots_" called ?

    in this example.

    #ifndef SIGNAL_HPP
    #define SIGNAL_HPP
    
    #include <functional>
    #include <map>
    
    // A signal object may call multiple slots with the
    // same signature. You can connect functions to the signal
    // which will be called when the emit() method on the
    // signal object is invoked. Any argument passed to emit()
    // will be passed to the given functions.
    
    template <typename... Args>
    class Signal {
    
     public:
    
      Signal() : current_id_(0) {}
    
      // copy creates new signal
      Signal(Signal const& other) : current_id_(0) {}
    
      // connects a member function to this Signal
      template <typename T>
      int connect_member(T *inst, void (T::*func)(Args...)) {
        return connect([=](Args... args) { 
          (inst->*func)(args...); 
        });
      }
    
      // connects a const member function to this Signal
      template <typename T>
      int connect_member(T *inst, void (T::*func)(Args...) const) {
        return connect([=](Args... args) {
          (inst->*func)(args...); 
        });
      }
    
      // connects a std::function to the signal. The returned
      // value can be used to disconnect the function again
      int connect(std::function<void(Args...)> const& slot) const {
        slots_.insert(std::make_pair(++current_id_, slot));
        return current_id_;
      }
    
      // disconnects a previously connected function
      void disconnect(int id) const {
        slots_.erase(id);
      }
    
      // disconnects all previously connected functions
      void disconnect_all() const {
        slots_.clear();
      }
    
      // calls all connected functions
      void emit(Args... p) {
        for(auto it : slots_) {
          it.second(p...);
        }
      }
    
      // assignment creates new Signal
      Signal& operator=(Signal const& other) {
        disconnect_all();
      }
    
     private:
      mutable std::map<int, std::function<void(Args...)>> slots_;
      mutable int current_id_;
    };
    
    #endif /* SIGNAL_HPP */
    

    How it's called so i can look for myself. Did i found overcomplicated example ?

Thanks.


Solution

  • Taking your questions in order:

    • Signal() : current_id_(0) {}

    That's a initialiser list in Signal's constructor. It tells the compiler that current_id_ should be initialized to 0 when the Signal object is constructed using that c'tor.

    • int connect_member(T *inst, void (T::*func)(Args...)) {

    T:: is a scope-resolution, and T::* specifically refers to a member function. The function call connect_member expects to receive a pointer-to-T, followed by a pointer-to-member-function-of-T (which takes unspecified arguments and returns nothing)

    • mutable std::map<int, std::function<void(Args...)>> slots_;

    slots_ is a data member of Signal, of type map from integer to function-returning-void. The mutable keyword tells the compiler it's ok for slots_ to be changed even if the owning Signal is const (for instance, inside a member function declared const).