Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. creating hash (or list) of member functions
Forum Updated to NodeBB v4.3 + New Features

creating hash (or list) of member functions

Scheduled Pinned Locked Moved Solved C++ Gurus
30 Posts 5 Posters 4.9k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • mzimmersM mzimmers

    @Chris-Kawa yeah, I'd actually gotten something working, but I like yours better, because it accepts the callback as an argument, rather than hardcoding it in the timer.

    I think this topic is closed, but I wonder if you could give me an explanation for the use of the std::bind. The list is just a list of QObjects; how does this "attach" the callback function?

    Thanks!

    Chris KawaC Offline
    Chris KawaC Offline
    Chris Kawa
    Lifetime Qt Champion
    wrote on last edited by Chris Kawa
    #15

    @mzimmers In my example it's not a list of QObjects. It's a list of std::function objects.
    Clock::update() is a class member function, so to call it you need an instance of that class i.e. instance->update(). The way class member functions work is that they really are just regular functions that have a hidden implicit this parameter, so in effect it's like Clock::update(instance).
    std::bind, as the name suggests, creates a callable object that binds a functor with a parameter, so you can call it as if there was no parameter.
    The way to think about it is that std::bind(cs, client) creates a struct with the operator(), something like this:

    struct Something
    {
       Clock* client;
       void operator()() { client->update(); }
    }
    

    so it turns a class member function with hidden this parameter into something that can be called without parameters. Then I just store it in a std::function object that can hold any type of callables (functions, functors, lambdas etc.).
    In other words std::bind creates something that holds information about both object and a function pointer, so you don't need anything extra to call it.

    JonBJ 1 Reply Last reply
    1
    • mzimmersM mzimmers

      @Chris-Kawa yeah, I'd actually gotten something working, but I like yours better, because it accepts the callback as an argument, rather than hardcoding it in the timer.

      I think this topic is closed, but I wonder if you could give me an explanation for the use of the std::bind. The list is just a list of QObjects; how does this "attach" the callback function?

      Thanks!

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #16

      @mzimmers said in creating hash (or list) of member functions:

      but I wonder if you could give me an explanation for the use of the std::bind. The list is just a list of QObjects; how does this "attach" the callback function?

      All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance. So...

      std::function<void()>
      

      I can be used to call a C++ class member method.

      registerClient(T* client, void(T::*cs)())
      

      Here's my client object (of a certain type), and here is the class member function.

      clients.push_back(std::bind(cs, client));
      

      Creates and pushes an object which, when invoked, will call cs(client). Which turns out to be the same as client->cs(). Which I am just about to question @Chris-Kawa on...!

      J.HilkJ 1 Reply Last reply
      0
      • Chris KawaC Chris Kawa

        @mzimmers In my example it's not a list of QObjects. It's a list of std::function objects.
        Clock::update() is a class member function, so to call it you need an instance of that class i.e. instance->update(). The way class member functions work is that they really are just regular functions that have a hidden implicit this parameter, so in effect it's like Clock::update(instance).
        std::bind, as the name suggests, creates a callable object that binds a functor with a parameter, so you can call it as if there was no parameter.
        The way to think about it is that std::bind(cs, client) creates a struct with the operator(), something like this:

        struct Something
        {
           Clock* client;
           void operator()() { client->update(); }
        }
        

        so it turns a class member function with hidden this parameter into something that can be called without parameters. Then I just store it in a std::function object that can hold any type of callables (functions, functors, lambdas etc.).
        In other words std::bind creates something that holds information about both object and a function pointer, so you don't need anything extra to call it.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #17

        @Chris-Kawa said in creating hash (or list) of member functions:

        The way class member functions work is that they really are just regular functions that have a hidden implicit this parameter, so in effect it's like Clock::update(instance).

        OMG! But where does C++ tell you this and that you can write code to use it? I had no idea this was "documented" or "supported". I assumed implementation was opaque/abstract.

        Chris KawaC 1 Reply Last reply
        0
        • JonBJ JonB

          @Chris-Kawa said in creating hash (or list) of member functions:

          The way class member functions work is that they really are just regular functions that have a hidden implicit this parameter, so in effect it's like Clock::update(instance).

          OMG! But where does C++ tell you this and that you can write code to use it? I had no idea this was "documented" or "supported". I assumed implementation was opaque/abstract.

          Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #18

          @JonB said:

          But where does C++ tell you this and that you can write code to use it?

          Well no, you can't currently write it like that. I meant it conceptually. That's just what the compiler does anyway (you can see it e.g. in the mangled function signatures when inspecting C++ library exports).

          Although the so called Uniform Call Syntax has been proposed multiple times over the years, including by Mr. C++ himself: N4474, so you might see it in some future standard version.

          JonBJ 1 Reply Last reply
          1
          • Chris KawaC Chris Kawa

            @JonB said:

            But where does C++ tell you this and that you can write code to use it?

            Well no, you can't currently write it like that. I meant it conceptually. That's just what the compiler does anyway (you can see it e.g. in the mangled function signatures when inspecting C++ library exports).

            Although the so called Uniform Call Syntax has been proposed multiple times over the years, including by Mr. C++ himself: N4474, so you might see it in some future standard version.

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #19

            @Chris-Kawa said in creating hash (or list) of member functions:

            Well no, you can't currently write it like that. I meant it conceptually.

            Oh, right! For a while there I thought you were saying literally.

            I suppose I ought go look at what magic std::bind() actually does, then it would be clear. But I just know it's going to look complicated.... :(

            Chris KawaC 1 Reply Last reply
            0
            • JonBJ JonB

              @Chris-Kawa said in creating hash (or list) of member functions:

              Well no, you can't currently write it like that. I meant it conceptually.

              Oh, right! For a while there I thought you were saying literally.

              I suppose I ought go look at what magic std::bind() actually does, then it would be clear. But I just know it's going to look complicated.... :(

              Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #20

              @JonB said:

              But I just know it's going to look complicated.... :(

              It does look a bit complicated, but it has to deal with variable number of perfectly forwarded arguments and a lot of weird corner cases users come up with. Also it's the standard library, so it's mangled with all those underscore names and defensive programming style, but if you squint a little you'll see it basically returns a class with operator() like I mentioned.

              JonBJ 1 Reply Last reply
              1
              • Chris KawaC Chris Kawa

                @JonB said:

                But I just know it's going to look complicated.... :(

                It does look a bit complicated, but it has to deal with variable number of perfectly forwarded arguments and a lot of weird corner cases users come up with. Also it's the standard library, so it's mangled with all those underscore names and defensive programming style, but if you squint a little you'll see it basically returns a class with operator() like I mentioned.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #21

                @Chris-Kawa
                Thanks. You gotta love hardcore C++, it's so... simple and clean.

                mzimmersM 1 Reply Last reply
                0
                • JonBJ JonB

                  @Chris-Kawa
                  Thanks. You gotta love hardcore C++, it's so... simple and clean.

                  mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by
                  #22

                  @JonB said in creating hash (or list) of member functions:

                  @Chris-Kawa
                  Thanks. You gotta love hardcore C++, it's so... simple and clean.

                  Now, now...no sarcasm.

                  But yeah...wouldn't you love to have today's compute resources available for solving the problems of 30 years ago?

                  1 Reply Last reply
                  0
                  • JonBJ JonB

                    @mzimmers said in creating hash (or list) of member functions:

                    but I wonder if you could give me an explanation for the use of the std::bind. The list is just a list of QObjects; how does this "attach" the callback function?

                    All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance. So...

                    std::function<void()>
                    

                    I can be used to call a C++ class member method.

                    registerClient(T* client, void(T::*cs)())
                    

                    Here's my client object (of a certain type), and here is the class member function.

                    clients.push_back(std::bind(cs, client));
                    

                    Creates and pushes an object which, when invoked, will call cs(client). Which turns out to be the same as client->cs(). Which I am just about to question @Chris-Kawa on...!

                    J.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #23

                    @JonB said in creating hash (or list) of member functions:

                    All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance

                    who says you can't ?

                    #include <array>
                    
                    class SomeClass : public QObject
                    {
                        Q_OBJECT
                        typedef void (SomeClass::*SomeClassFunction)();
                    
                        std::array<SomeClassFunction,3> arrayOfSignalsPointers{&SomeClass::signal1,&SomeClass::signal2, &SomeClass::signal3};
                        std::array<SomeClassFunction, 3> arrayOfSlotsPointers{&SomeClass::slot1, &SomeClass::slot2, &SomeClass::slot3};
                    
                    public:
                        explicit SomeClass(QObject *parent = nullptr) : QObject(parent)
                        {
                            QObject::connect(this, &SomeClass::signal1, this, &SomeClass::slot1);
                            QObject::connect(this, &SomeClass::signal2, this, &SomeClass::slot2);
                            QObject::connect(this, &SomeClass::signal3, this, &SomeClass::slot3);
                    
                            qDebug() << "Emit all signals";
                            for(auto entry : arrayOfSignalsPointers){
                                (this->*entry)();
                            }
                    
                            qDebug() << "Call all slots directly";
                            for(auto entry : arrayOfSlotsPointers){
                                (this->*entry)();
                            }
                        }
                    
                    signals:
                        void signal1();
                        void signal2();
                        void signal3();
                    
                    public slots:
                        void slot1(){qDebug() <<  Q_FUNC_INFO;}
                        void slot2(){qDebug() <<  Q_FUNC_INFO;}
                        void slot3(){qDebug() <<  Q_FUNC_INFO;}
                    };
                    

                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    JonBJ 1 Reply Last reply
                    1
                    • J.HilkJ J.Hilk

                      @JonB said in creating hash (or list) of member functions:

                      All of this in place of the typedef void (*clientSlot)(), with C life used to be so simple :) We can't use that to call a C++ class member function on an instance

                      who says you can't ?

                      #include <array>
                      
                      class SomeClass : public QObject
                      {
                          Q_OBJECT
                          typedef void (SomeClass::*SomeClassFunction)();
                      
                          std::array<SomeClassFunction,3> arrayOfSignalsPointers{&SomeClass::signal1,&SomeClass::signal2, &SomeClass::signal3};
                          std::array<SomeClassFunction, 3> arrayOfSlotsPointers{&SomeClass::slot1, &SomeClass::slot2, &SomeClass::slot3};
                      
                      public:
                          explicit SomeClass(QObject *parent = nullptr) : QObject(parent)
                          {
                              QObject::connect(this, &SomeClass::signal1, this, &SomeClass::slot1);
                              QObject::connect(this, &SomeClass::signal2, this, &SomeClass::slot2);
                              QObject::connect(this, &SomeClass::signal3, this, &SomeClass::slot3);
                      
                              qDebug() << "Emit all signals";
                              for(auto entry : arrayOfSignalsPointers){
                                  (this->*entry)();
                              }
                      
                              qDebug() << "Call all slots directly";
                              for(auto entry : arrayOfSlotsPointers){
                                  (this->*entry)();
                              }
                          }
                      
                      signals:
                          void signal1();
                          void signal2();
                          void signal3();
                      
                      public slots:
                          void slot1(){qDebug() <<  Q_FUNC_INFO;}
                          void slot2(){qDebug() <<  Q_FUNC_INFO;}
                          void slot3(){qDebug() <<  Q_FUNC_INFO;}
                      };
                      
                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #24

                      @J-Hilk said in creating hash (or list) of member functions:

                      typedef void (SomeClass::*SomeClassFunction)();

                      I said that you cannot use typedef void (*clientSlot)();, as the OP wrote and one would in C, to call a C++ member function. And you can't: as you show you need ClassName::*function not just plain *function.

                      Having said that, I was nonetheless not aware that you can use that to get a member function's address and then call (instance->*memberFunctionPointer)(). Thank you for clarifying.

                      So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)

                      Chris KawaC 1 Reply Last reply
                      1
                      • JonBJ JonB

                        @J-Hilk said in creating hash (or list) of member functions:

                        typedef void (SomeClass::*SomeClassFunction)();

                        I said that you cannot use typedef void (*clientSlot)();, as the OP wrote and one would in C, to call a C++ member function. And you can't: as you show you need ClassName::*function not just plain *function.

                        Having said that, I was nonetheless not aware that you can use that to get a member function's address and then call (instance->*memberFunctionPointer)(). Thank you for clarifying.

                        So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)

                        Chris KawaC Offline
                        Chris KawaC Offline
                        Chris Kawa
                        Lifetime Qt Champion
                        wrote on last edited by
                        #25

                        @JonB said:

                        So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)

                        No, it's a way to be generic. To write typedef void (SomeClass::*SomeClassFunction)() you have to hardcode SomeClass i.e. know it up front. Notice that what @J-Hilk posted will work with one particular class only. I know he just shows how to call a member function from a pointer and that's fine, but it doesn't do much for the original problem.
                        std::function doesn't care. It just takes any functor you give it and std::bind creates a functor from anything callable you give it.

                        JonBJ 1 Reply Last reply
                        2
                        • Chris KawaC Chris Kawa

                          @JonB said:

                          So.... all this std::function<> and particularly std::bind() looks like the usual C++ "why would you want to write something simple when you can wrap it up to be complicated"? ;-)

                          No, it's a way to be generic. To write typedef void (SomeClass::*SomeClassFunction)() you have to hardcode SomeClass i.e. know it up front. Notice that what @J-Hilk posted will work with one particular class only. I know he just shows how to call a member function from a pointer and that's fine, but it doesn't do much for the original problem.
                          std::function doesn't care. It just takes any functor you give it and std::bind creates a functor from anything callable you give it.

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by
                          #26

                          @Chris-Kawa
                          Ah yes, I get it.

                          Modern C++ programming is hugely about templates. But, correct me if I am wrong, C++ did not start out with templates, did it?

                          J.HilkJ 1 Reply Last reply
                          0
                          • JonBJ JonB

                            @Chris-Kawa
                            Ah yes, I get it.

                            Modern C++ programming is hugely about templates. But, correct me if I am wrong, C++ did not start out with templates, did it?

                            J.HilkJ Offline
                            J.HilkJ Offline
                            J.Hilk
                            Moderators
                            wrote on last edited by
                            #27

                            @JonB proposed in 1988, realised in 1990 so a decade after the "initial commit" :P


                            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                            Q: What's that?
                            A: It's blue light.
                            Q: What does it do?
                            A: It turns blue.

                            JonBJ Chris KawaC 2 Replies Last reply
                            2
                            • J.HilkJ J.Hilk

                              @JonB proposed in 1988, realised in 1990 so a decade after the "initial commit" :P

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by
                              #28

                              @J-Hilk Ah, thanks, that is much earlier than I realized, I thought more like 10 years later.

                              1 Reply Last reply
                              0
                              • J.HilkJ J.Hilk

                                @JonB proposed in 1988, realised in 1990 so a decade after the "initial commit" :P

                                Chris KawaC Offline
                                Chris KawaC Offline
                                Chris Kawa
                                Lifetime Qt Champion
                                wrote on last edited by
                                #29

                                @J-Hilk Where "initial commit" at that time would probably be Stroustrup saving it to a big floppy and physically carrying it to the cubicle of his coworkers. Good old times :D

                                JonBJ 1 Reply Last reply
                                0
                                • Chris KawaC Chris Kawa

                                  @J-Hilk Where "initial commit" at that time would probably be Stroustrup saving it to a big floppy and physically carrying it to the cubicle of his coworkers. Good old times :D

                                  JonBJ Offline
                                  JonBJ Offline
                                  JonB
                                  wrote on last edited by
                                  #30

                                  @Chris-Kawa

                                  We were beyond floppies by then. The first computer I used had 10.5 inch (I think, unless it was only 8 inch) floppies, https://www.computinghistory.org.uk/det/10247/Nord-ND305-355-Floppy-Disk/ :)

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved