for_each für Memberfunktionen?



  • Hallo,

    ich würde gerne mal wissen ob folgendes eigentlich möglich ist, also ich habe es jedenfalls nicht hinbekommen.

    Gegeben folgende Klassen

    class A{
      A();
      ...
    };
    
    class B{
      B();
      void fkt1();
      void fkt2(A& A);
    
      std::vector< A > vec;
    };
    

    Kann man irgendwie von der Funktion fkt1() aus mittels for_each die fkt2() für jedes Element aus vec aufrufen?

    Also etwas in der Art:

    void B::fkt1(){
      for_each(vec.begin(), vec.end(), fkt2);
    }
    

    Funktioniert natürlich so nicht, aber kann man das mit for_each ausdrücken, oder muss man eine for-Schleife schreiben und von Hand über den Vector iterieren?
    So wäre es natürlich auch möglich:

    for(unsigned int i=0; i<vec.size(); ++i){
      fkt2(vec[i]);
    }
    

    Oder natürlich mit Iteratoren.



  • Weit davon entfernt, mich mit for_each auszukennen, möchte ich behaupten, dass wohl kein Weg daran vorbei führt, die Funktion mit Pointer oder Iterator aufzurufen.



  • Edit: Sorry, hatte überlesen, dass es sich um Memberfunktionen handelt.



  • Da hilft dir entweder std::tr1::bind oder, wenn du keine TR1-Stdlib hast mit std::mem_fun und std::bind1st:

    std::for_each(vec.begin(), vec.end(), std::tr1::bind(&B::fkt2, this));
    //oder
    std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun(&B::fkt2), *this));
    

  • Administrator

    @.filmor,
    Ich kenne mich mit dem std::tr1::bind nicht so genau aus, aber ich dachte, es wäre dem von Boost ähnlich bis gleich. Dann fehlt bei deinem Code nämlich noch was, denn mit Boost, geht es so:

    std::for_each(vec.begin(), vec.end(), boost::bind(&B::fkt2, this, _1));
    

    Eine weitere Alternative gibt es auch noch:

    void B::fkt1()
    {
      struct CallFkt2
      {
        B* b;
    
        void operator ()(A& a) const { b->fkt2(a); };
      };
    
      CallFkt2 temp;
      temp.b = this;
      std::for_each(vec.begin(), vec.end(), temp);
    }
    

    Grüssli



  • /edit: hatte was überlesen



  • std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun(&B::fkt2), *this));
    

    Das wäre eigentlich das gewesen, was ich gesucht habe, kompiliert aber leider nicht bei mir.

    Muss ich ausser algorithm und functional vielleicht noch irgendwelche Header einbinden?

    Ich bekomme leider eine riesen Fehlermeldung (DependencyGraph ist hier meine Klasse B und dgNode ist A).

    /usr/include/c++/4.2/bits/stl_function.h: In instantiation of ‘std::binder1st<std::mem_fun1_t<void, DependencyGraph, dgNode&> >’:
    /src/DependencyGraph/DependencyGraph.cpp:164:   instantiated from here
    /usr/include/c++/4.2/bits/stl_function.h:405: error: forming reference to reference type ‘dgNode&’
    /usr/include/c++/4.2/bits/stl_function.h:411: error: forming reference to reference type ‘dgNode&’
    /usr/include/c++/4.2/bits/stl_function.h: In function ‘std::binder1st<_Operation> std::bind1st(const _Operation&, const _Tp&) [with _Operation = std::mem_fun1_t<void, DependencyGraph, dgNode&>, _Tp = DependencyGraph]’:
    /src/DependencyGraph/DependencyGraph.cpp:164:   instantiated from here
    /usr/include/c++/4.2/bits/stl_function.h:421: error: invalid cast from type ‘const DependencyGraph’ to type ‘DependencyGraph*’
    /usr/include/c++/4.2/bits/stl_algo.h: In function ‘_Function std::for_each(_InputIterator, _InputIterator, _Function) [with _InputIterator = __gnu_cxx::__normal_iterator<dgNode*, std::vector<dgNode, std::allocator<dgNode> > >, _Function = std::binder1st<std::mem_fun1_t<void, DependencyGraph, dgNode&> >]’:
    /src/DependencyGraph/DependencyGraph.cpp:164:   instantiated from here
    /usr/include/c++/4.2/bits/stl_algo.h:159: error: no match for call to ‘(std::binder1st<std::mem_fun1_t<void, DependencyGraph, dgNode&> >) (dgNode&)’
    

    Irgendwie habe ich das Gefühl, dass wenn der Aufruf von for_each derart kompliziert ist, dass eine Schleife vielleicht doch das elegantere Mittel ist. Schade eigentlich.



  • Dravere schrieb:

    @.filmor,
    Ich kenne mich mit dem std::tr1::bind nicht so genau aus, aber ich dachte, es wäre dem von Boost ähnlich bis gleich. Dann fehlt bei deinem Code nämlich noch was, denn mit Boost, geht es so:

    std::for_each(vec.begin(), vec.end(), boost::bind(&B::fkt2, this, _1));
    

    Tatsache. War das schon immer so? Dann hatte ich wohl einfach Glück mit meinem Code 😉

    Jiddoo schrieb:

    std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun(&B::fkt2), *this));
    

    Das wäre eigentlich das gewesen, was ich gesucht habe, kompiliert aber leider nicht bei mir.

    Probier mal this statt *this .



  • .filmor schrieb:

    Dravere schrieb:

    @.filmor,
    Ich kenne mich mit dem std::tr1::bind nicht so genau aus, aber ich dachte, es wäre dem von Boost ähnlich bis gleich. Dann fehlt bei deinem Code nämlich noch was, denn mit Boost, geht es so:

    std::for_each(vec.begin(), vec.end(), boost::bind(&B::fkt2, this, _1));
    

    Tatsache. War das schon immer so? Dann hatte ich wohl einfach Glück mit meinem Code 😉

    Bei boost::bind schon immer (seit ich es kenne, also min. seit boost version 1.33), ja. bei std::tr1::bind nehme ich an wird es auch so sein.


  • Administrator

    @Jiddoo,

    std::for_each(vec.begin(), vec.end(), std::bind1st(std::mem_fun(&B::fkt2), this));
    

    Wird leider nicht funktionieren, da B::fkt2 ein A& erwartet. Es müsste ein A sein, also keine Referenz. Der C++ Standard ist in diesen Belangen irgendwie äusserst hässlich.
    Für sowas ist wirklich Boost.Bind, std::tr1::bind oder das struct zu empfehlen. Oder du machst es einfach "manuell". Im zukünftigen Standard wird sich dies aber zum Glück ändern.

    Übrigens ist Boost auch sonst sehr zu empfehlen. Also falls du es noch nicht hast, ruhig mal anschauen 🙂

    @.filmor

    boost::bind(&B::fkt2, this)
    

    Ist gleich einer Memberfunktion ohne Parameter.

    boost::bind(&B::fkt2, this, _1)
    

    Sagt, dass es einen Parameter hat.

    boost::bind(&B::fkt2, this, _1, _2)
    

    Zwei parameter ... usw. 😉

    War so, seit ich mich erinnern kann.

    Grüssli



  • std::for_each(vec.begin(), vec.end(), boost::bind(&B::fkt2, this, _1));

    Das hat funktioniert. 🙂
    Mit dem tr1 hab ich es nicht hinbekommen, aber vielleicht habe ich da auch noch was in den Compilersettings falsch gehabt.

    Boost scheint wirklich unglaublich praktisch zu sein. Wenn ich jetzt noch die Zeit hätte mich da intensiv mit zu beschäftigen... 😉

    Vielen Dank an alle.



  • Beim TR1 dürfte ein using std::tr1::placeholders im Funktionsrumpf helfen...



  • Jiddoo schrieb:

    Boost scheint wirklich unglaublich praktisch zu sein. Wenn ich jetzt noch die Zeit hätte mich da intensiv mit zu beschäftigen... 😉

    Ja, Boost bietet unheimlich mächtige Mittel. Ich beschäftige mich auch noch nicht so lange mit den Boost C++ Libraries, aber ich bin immer wieder von neuem erstaunt. 😉


Anmelden zum Antworten