Slots? Callbacks? Wrapper?



  • Bei dem bind fehlen ja auch die beiden Parameter, also hier "_1" und "_2".



  • @Jockelx 🤦🏼♂ Danke...



  • Gibt es eine Möglichkeit das bind in die Klasse zu verlagern?
    Die Intention wäre, dass die Verbindungsfunktionen unabhängig davon ob sie aus einer fremden Klasse oder "frei" aufgerufen werden, gleich aussehen, also nur eine(n) Funktion(spointer) erhalten.



  • @DaRaRa sagte in Slots? Callbacks? Wrapper?:

    Gibt es eine Möglichkeit das bind in die Klasse zu verlagern?
    Die Intention wäre, dass die Verbindungsfunktionen unabhängig davon ob sie aus einer fremden Klasse oder "frei" aufgerufen werden, gleich aussehen, also nur eine(n) Funktion(spointer) erhalten.

    Verstehe ich noch nicht ganz. Dein Algorithmus hat doch kein std::bind etc. mehr drin. Also sprich connect_function_x weiß nicht mehr, ob es sich um eine member funktion oder nicht handelt. Beim Aufruf, also aktuell in der Qt_slot Methode, wird es aktuell gemacht. Da ist doch gut, weil deine Qt_Gui weiß ja, ob es sich um eine member funktion handelt oder nicht.

    Ggf. kannst du nochmal konkret das Problem zeigen. Hast du Code, der quasi aktuell nicht funktioniert? Oder was stört dich genau?

    P.S. Sofern du C++20 verwendest, kannst du auch std::bind_front nutzen. Das bindet nur den ersten Parameter und funktioniert daher ohne die Placeholder. Siehe https://en.cppreference.com/w/cpp/utility/functional/bind_front.
    Damit würde deine Code von oben funktionieren, wo du bei std::bin noch die placeholder hinzufügen musstest.



  • Sorry, das mit den Placeholdern hatte ich vergessen. Und danke @Leon0402 für den Link auf std::bind_front.



  • Danke an alle für die Antworten!

    Ich habe mich falsch ausgedrückt:
    Was mich stört ist, dass die Aufrufe der connect_*-Funktionen anders aussehen, je nachdem von welcher Klasse aus sie aufgerufen werden:
    Rufe ich sie aus dem Qt-Kontext auf lautet der Aufruf
    algo.connect_function_x(std::bind(&Qt_GUI::function_x, this, _1, _2));
    aus dem freien Kontext
    algo.connect_function_x(function_x);
    aber da führt wohl kein Weg daran vorbei.?



  • Ich bastel grad an was Ähnlichem, vielleicht kannste was damit anfangen:

    #include <string>
    #include <functional>
    #include <iostream>
    
    // Test signature
    using Callback_t = std::function<void( unsigned int , std::string const& value )>;
    
    /***************************************************************************************************
    *                                                                                                  *
    * Pointer to non-const member function of non-const Object                                         *
    *                                                                                                  *
    ***************************************************************************************************/
    template<typename ReturnType, typename ObjectType, typename ...Params>
    std::function<ReturnType( Params...)> make_callback( ObjectType& obj, ReturnType (ObjectType::*mem_fun)( Params... ) )
    {
       auto Invoker = [&obj, mem_fun]( Params... params ) -> ReturnType
       {
          return std::invoke( mem_fun, obj, std::forward<Params>( params )... );
       };
       return std::function<ReturnType( Params... )>( Invoker );
    }
    
    /***************************************************************************************************
    *                                                                                                  *
    * Pointer to const member function of non-const Object                                             *
    *                                                                                                  *
    ***************************************************************************************************/
    template<typename ReturnType, typename ObjectType, typename ...Params>
    std::function<ReturnType( Params...)> make_callback( ObjectType& obj, ReturnType (ObjectType::*mem_fun)( Params... ) const )
    {
       auto Invoker = [&obj, mem_fun]( Params... params ) -> ReturnType
       {
          return std::invoke( mem_fun, obj, std::forward<Params>( params )... );
       };
       return std::function<ReturnType( Params... )>( Invoker );
    }
    
    /***************************************************************************************************
    *                                                                                                  *
    * Pointer to const member function of const Object                                                 *
    *                                                                                                  *
    ***************************************************************************************************/
    template<typename ReturnType, typename ObjectType, typename ...Params>
    std::function<ReturnType( Params...)> make_callback( ObjectType const& obj, ReturnType (ObjectType::*mem_fun)( Params... ) const )
    {
       auto Invoker = [&obj, mem_fun]( Params... params ) -> ReturnType
       {
          return std::invoke( mem_fun, obj, std::forward<Params>( params )... );
       };
       return std::function<ReturnType( Params... )>( Invoker );
    }
    
    /***************************************************************************************************
    *                                                                                                  *
    * Free function                                                                                    *
    *                                                                                                  *
    ***************************************************************************************************/
    template<typename ReturnType, typename ...Params>
    std::function<ReturnType( Params...)> make_callback( ReturnType (*free_fun)( Params... ) )
    {
       return std::function<ReturnType( Params... )>( free_fun );
    }
    
    
    
    struct Test
    {
    	void function(  unsigned int id, std::string const& value ) const
    	{
    		std::cout << "member function: Id: " << id << ", value: " << value << "\n";
    	}
    
    };
    
    
    
    void free_func( unsigned int id, std::string const& value ) 
    {
    		std::cout << "free function: Id: " << id << ", value: " << value << "\n";
    }
    
    void int main()
    {
    	Test s0;
    	Test const s1;
    
    	Callback_t cb0 = make_callback( s0, &Test::function );
    	cb0( 4710, std::string( "Hello World" ) );
    	
    	Callback_t cb1 = make_callback( s1, &Test::function );
    	cb1( 4711, std::string( "Hello World" ) );
    
    	Callback_t cb2 = make_callback( &free_func );
    	cb2( 4712, std::string( "Hello World" ) );
    }
    


  • @DaRaRa sagte in Slots? Callbacks? Wrapper?:

    Danke an alle für die Antworten!

    Ich habe mich falsch ausgedrückt:
    Was mich stört ist, dass die Aufrufe der connect_*-Funktionen anders aussehen, je nachdem von welcher Klasse aus sie aufgerufen werden:
    Rufe ich sie aus dem Qt-Kontext auf lautet der Aufruf
    algo.connect_function_x(std::bind(&Qt_GUI::function_x, this, _1, _2));
    aus dem freien Kontext
    algo.connect_function_x(function_x);
    aber da führt wohl kein Weg daran vorbei.?

    Naja du musst es ja nicht in einer Zeile machen. Also sprich, du kannst auch den std::bind Aufruf irgendwo früher machen und in ner Variable function_x speichern. Oder alternativ statt std::bind auch ein Lambda nutzen.

    Aber vlt. versuchst du nochmal zu erklären / herauszufinden, warum es dich stört, dass die Aufrufe anders aussehen. Grundsätzlich ist das ja erstmal erwartbar, dass der Aufruf anders aussieht, wenn man unterschiedliche Dinge macht. Okay nehmen wir mal die Besonderheit mit std::bind und den Member Funktionen weg. Selbst dann wäre die Syntax ja mindestens sowas wie:

    algo.connect_function_x(&Qt_GUI::function_x);
    algo.connect_function_x(&function_x);
    

    Ist ja irgendwie auch logisch ... irgendwie musst du ha zwischen einer freien Funktion function_x und einer Funktion in einer Klasse, Namespace etc. unterscheiden können. Deswegen spricht aus meiner Sicht erstmal nichts grundsätzlich dagegen, dass die Aufrufe anders aussehen. Im Gegenteil das ist sogar sehr sinnvoll 😃

    Die eigentliche Syntax ist etwas komplexer. Aber auch das ergibt grundsätzlich Sinn. Member Funktionen müssen ja auf irgendeinem Objekt aufgerufen werden. Das wäre oben in dem Call ja gar nicht encodiert. Das kannst du aber wie gesagt auch schöner machen in C++20*:

    algo.connect_function_x(std::bind_front(&Qt_GUI::function_x, this));
    

    Wenn dich trotzdem irgendwas stört, dann gibt es dafür zwei recht wahrscheinliche Gründe:
    a) Du verschweigst uns irgendein "echtes" Problem noch, welches sich aus der unterschiedlichen Syntax ergibt
    b) Du hast irgendwas nicht so ganz verstanden, sodass es dir seltsam / unnötig komplex vorkommt, dass die Syntax anders ist

    In beiden Fällen ergibt es Sinn, wenn du versuchst genauer zu erklären, was genau dein Problem ist.

    • Mir würde so eine Syntax noch ganz gut gefallen:
    algo.connect_function_x(&this->function_x);
    

    Das wird meines Wissens nach aber nicht unterstützt. Also quasi ein "automatisches binden". Das macht dann aber vermutlich in anderen Fällen wieder Probleme, wo man das nicht will.



  • @Leon0402: Du meinst std::bind_front?! 😉

    // ab C++20
    algo.connect_function_x(std::bind_front(&Qt_GUI::function_x, this));
    


  • @Th69 sagte in Slots? Callbacks? Wrapper?:

    @Leon0402: Du meinst std::bind_front?! 😉

    // ab C++20
    algo.connect_function_x(std::bind_front(&Qt_GUI::function_x, this));
    

    Da ist man mal einmal unaufmerksam 😃 Danke, ist gefixt.


Anmelden zum Antworten