boost::function mit konstanter Referenz und std::bind1st



  • Hallo zusammen.

    In meinem Programm möchte ich gerne die Abhängigkeit zu boost::bind loswerden und schwenke daher auf boost::function um.

    Möglich soll es sein, dass Funktionsobjekte folgender Signatur in einer std::map hinterlegt werden können:

    void( const Event & )
    

    Event ist eine Klasse.

    Die Deklaration von boost::function schaut bei mir so aus:

    typedef boost::function<void( const Event & )>  Blubb;
    

    Der Code zum Ablegen und Aufrufen der Funktionsobjekte funktioniert soweit. Aufgerufen wird folgendermaßen:

    (fktobj)( boost::cref( parameter ) );
    

    Probleme macht allerdings dann das Konstruieren eines Funktionsobjektes:

    Blubb  f( std::bind1st( std::mem_fun( &MeineKlasse::MeineFunktion ), this ) );
    

    Fehlermeldung:

    /usr/include/c++/4.3/backward/binders.h: In instantiation of 'std::binder1st<std::mem_fun1_t<void, EditboxSample, sfg::Event&> >':
    Editbox.cpp:81:   instantiated from here
    /usr/include/c++/4.3/backward/binders.h:120: error: 'typename _Operation::result_type std::binder1st<_Operation>::operator()(typename _Operation::second_argument_type&) const [with _Operation = std::mem_fun1_t<void, EditboxSample, sfg::Event&>]' cannot be overloaded
    /usr/include/c++/4.3/backward/binders.h:114: error: with 'typename _Operation::result_type std::binder1st<_Operation>::operator()(const typename _Operation::second_argument_type&) const [with _Operation = std::mem_fun1_t<void, EditboxSample, sfg::Event&>]'
    

    Die fehlerhafte Zeile ist halt obige mit der Konstruktion des Funktionsobjekts. Ich stehe mit meinem Latein völlig am Ende, weil ich mich sogar an einige Beispiele, die ich im Netz so fand, gehalten habe, den Fehler aber einfach nicht entdecken kann. Ich wäre sehr dankbar, wenn jemand einen Tipp hätte. 🙂

    Gruß,
    Stefan.



  • Stefan__ schrieb:

    In meinem Programm möchte ich gerne die Abhängigkeit zu boost::bind loswerden und schwenke daher auf boost::function um.

    Komisch. Das eine ist aber nicht durch das andere ersetzbar. Es sind recht unterschiedliche Dinge, die eigentlich auch gerne zusammen benutzt werden.

    [...]

    Stefan__ schrieb:

    Probleme macht allerdings dann das Konstruieren eines Funktionsobjektes:

    Blubb  f( std::bind1st( std::mem_fun( &MeineKlasse::MeineFunktion ), this ) );
    

    Fehlermeldung:

    /usr/include/c++/4.3/backward/binders.h: In instantiation of 'std::binder1st<std::mem_fun1_t<void, EditboxSample, sfg::Event&> >':
    Editbox.cpp:81:   instantiated from here
    /usr/include/c++/4.3/backward/binders.h:120: error: 'typename _Operation::result_type std::binder1st<_Operation>::operator()(typename _Operation::second_argument_type&) const [with _Operation = std::mem_fun1_t<void, EditboxSample, sfg::Event&>]' cannot be overloaded
    /usr/include/c++/4.3/backward/binders.h:114: error: with 'typename _Operation::result_type std::binder1st<_Operation>::operator()(const typename _Operation::second_argument_type&) const [with _Operation = std::mem_fun1_t<void, EditboxSample, sfg::Event&>]'
    

    Das ist ein Defekt im Standard. Die STL-Binder kommen mit Referenzparametern nicht klar. Im Binder wird versucht folgendes zu überladen:

    void operator()(const A &) const;
      void operator()(      A &) const;
    

    wobei A allerdings selbst eine Referenz ist, (A = const Event&). Das geht also schief. Eigentlich müsste eine "Referenz auf Referenz geht nicht"-Fehlermeldung bekommen, aber vielleicht kompilierst Du schon im C++0x Modus, welcher "& &" zu "&" zusammenfaltet. Das const hat auf eine Referenz keine Wirkung, weil eine Referenz schon intrinsisch const ist. Die Parametertypen der beiden Funktionen sind also identisch und können deshalb nicht überladen werden.

    Lösungen:
    (1) Boost.Bind benutzen,
    (2) einen eigenen Elementfunktions-Wrapper schreiben, der std::bind1st und std::mem_fun auf einmal ersetzt.
    (3) oder auf std::bind und std::function von C++0x warten

    Gruß,
    SP



  • Sebastian Pizer schrieb:

    (2) einen eigenen Elementfunktions-Wrapper schreiben, der std::bind1st und std::mem_fun auf einmal ersetzt.

    Oder die gleichnamigen Funktoren von Boost benutzen, soweit ich weiss, sollten die funktionieren. Allerdings kann man dann auch gleich die generische Variante boost::bind benutzen.



  • Sebastian Pizer schrieb:

    Eigentlich müsste eine "Referenz auf Referenz geht nicht"-Fehlermeldung bekommen, aber vielleicht kompilierst Du schon im C++0x Modus, welcher "& &" zu "&" zusammenfaltet.

    Genau das mache ich. Mir sind bei der Fehlermeldung die beiden unterschiedlichen (nunja, eigentlich ja gleichen, wie du schön erklärt hast) Signaturen aufgefallen. Ich hätte auch wirklich nicht gewusst, wie ich das hätte auflösen sollen -- nun weiß ich, dass das gar nicht geht.

    Die Parametertypen der beiden Funktionen sind also identisch und können deshalb nicht überladen werden.

    Vielen Dank für die Erklärung, sie bescherte mir einen guten "Aha!"-Effekt. 🙂

    (1) Boost.Bind benutzen,

    Das werde ich auch tun. Nach etwas weiterem Überlegen ist mir nämlich mein eigentliches Problem aufgefallen: Ich hatte Funktionsobjekte zuvor über Boost.Signals abgelegt, brauche aber die Funktionalität der Signals und Slots gar nicht. Daher werde ich nun einfach boost::function und boost::bind nutzen, welche beide Header-only sind und daher als Abhängigkeiten völlig okay sind. Die Sache ist einfach die, dass ich für ein aktuelles Projekt den Setup-Aufwand möglichst gering halten möchte.

    (3) oder auf std::bind und std::function von C++0x warten

    Hachja, auf C++0x warten wir doch alle. 😉

    Jedenfalls danke ich dir für deine Antwort, hat mir sehr weitergeholfen,
    Stefan.


Anmelden zum Antworten