Search code examples
c++c++11observer-patternstdbind

bind class function observer c++11


I'm trying to extend a subject observer pattern to take a function from a class rather than a static function. I've followed juan chopanza EXCELLENT example at Simple Observer Pattern c++11 Now I'd like to pass a class member function as the registered call back rather than a simple function.

I've realized that I can call a class member by using a bind(&class::member,instance) as per the following:

class A {
public:
    void A_Bar() { std::cout << "A" << m_nTest << "_bar()" << std::endl; }
    void A_Foo(int n) { std::cout << "A" << m_nTest << "_Foo(" << n << ")" << std::endl; }
    int m_nTest;
};

int main(int argc, _TCHAR* argv[])
{
    A A1; A1.m_nTest = 1;
    A A2; A2.m_nTest = 2;
    Subject<EventType> s;
    s.registerObserver(EventType::GREEN, bar);
    s.registerObserver(EventType::GREEN, std::bind(&A::A_Bar, A2));
    s.registerObserver(EventType::GREEN, std::bind(&A::A_Bar, A1));
    s.notify(EventType::GREEN);
}

Since the first parameter on becomes the class from which it's called. I get exactly what I'd like:

  • bar()
  • A2_bar()
  • A1_bar()

But now I want to also have the notify pass some information to the observer class. Thus I have modified the code to the following:

template <typename Event>
class Subject
{...
  void notify(const Event& event, int nParameter) const
  {
      for (const auto& obs : observers_.at(event)) obs(nParameter);
  }
 private:
  std::map<Event, std::vector<std::function<void(int)>>> observers_;
};

And now my I'd like to register:

    s.registerObserver(EventType::GREEN, std::bind(&A::A_Foo, A2));

Can anyone help me out what I'm missing or how to do this. I don't really want to make my Subject class know about the Observer class by adding it into the function interface. Thanks


Solution

  • Your code using bind may be problematic since it copies the objects A2 and A1, you can use &A2 and &A2 if you want to reference the original objects. To answer your question, you can use:

    s.registerObserver(EventType::GREEN, std::bind(&A::A_Foo, &A2, std::placeholders::_1));
    

    Or use lambda, which I'd recommend:

    s.registerObserver(EventType::GREEN, [&](int i){ A2.A_Foo(i); });