Liste von Callback-Funktionspointern abarbeiten - elegante Lösung gesucht.



  • Servus,

    an diesem Gedankenspiel sind zwei Partner beteiligt: Die Klasse Client, die eine Callbackfunktion hat, die aufgerufen werden soll, wenn verschiedene asynchrone Anfragen ausgeführt wurden, und die Klasse Manager, die eben diese Anfragen abarbeitet.

    Jetzt gibt es einen Manager und viele Clients.
    Die Idee ist, dass sich Clients im Konstruktor bei Manager anmelden, und der eine Liste von Funktionspointern abspeichert. Bei Fertigstellung einer Aufgabe sollen diese Funktionspointer abgeklappert werden.

    Soviel habe ich bis jetzt:

    class Client {
    public:
      Client(Manager& manager);
      void doStuff() { /*whatever*/ }
    }
    
    Client::Client(Manager& manager)
    {
      manager.registerCallback(std::bind1st(
          std::mem_fun(&Client::doStuff), this));
    }
    
    class Manager {
    public:
      void registerCallback(boost::function<void(void)> fun);
      void process();
    private:
      std::list<boost::function<void(void)> > m_callbacks;
    }
    
    void Manager::registerCallback(boost::function<void(void)> fun)
    {
      m_callbacks.push_back(fun);
    }
    void Manager::process()
    {
      for_each(m_callbacks.begin(), m_callbacks.end(), /* und was nun? */);
    }
    

    Prinzip sollte klar sein: Memberfunktion wird gebunden und dem Manger übergeben, der Sie in die Liste pusht.
    Wie kann der Manager jetzt die Liste abarbeiten? Wie invoke ich denn den Funktionspointer über seinen Iterator? *verwirrt*

    EDIT: Nochwas: Geht das auch mit "echten" Funktionspointern, also ohne boost? Irgendwie steh ich mit den echten auf Kriegsfuß, weil die sich nie so binden lassen wie ich will.

    Danke für gute Ideen,
    Phil



  • Der Algorithmus std::for_each() kommt mir hier nicht sehr geeignet vor. Wie wärs mit einer normalen Iterationsschleife?

    void Manager::process()
    {
      // callback_list ist ein typedef
      for (callback_list::iterator itr = m_callbacks.begin(), end = m_callbacks.end(); itr != end; ++itr)
        (*itr)();
    }
    

    Oder sonst eben eine Extrafunktion:

    void call(boost::function<void(void)>& fn)
    {
    	fn();
    }
    
    void Manager::process()
    {
      std::for_each(m_callbacks.begin(), m_callbacks.end(), &call);
    }
    

    Native Memberfunktionszeiger würden schon auch funktionieren, wären allerdings sehr eingeschränkt. Binden wäre damit nicht möglich. Für die Syntax kannst du dir http://www.newty.de/fpt/index.html anschauen.



  • Super. Funzt.



  • Übrigens, genau das, was du hier implementierst, bietet boost.Signals.



  • Stimmt. Die Entwickler von Boost.Signals haben zum Beispiel auch einen Weg gefunden, gespeicherte Funktionen wieder zu löschen. Eine Löschung ist aufgrund der fehlenden Möglichkeit, boost::function zu vergleichen, nämlich nicht ganz trivial.

    Dazu habe ich vor einiger Zeit übrigens einen Thread erstellt.




Anmelden zum Antworten