Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Is it possible to mimic the functionality of an array of signals?
Forum Updated to NodeBB v4.3 + New Features

Is it possible to mimic the functionality of an array of signals?

Scheduled Pinned Locked Moved Solved Mobile and Embedded
12 Posts 5 Posters 852 Views
  • 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.
  • J jsulm
    29 Jun 2021, 12:43

    @JeKK666 Why don't you use a mapping between key and method pointer? Then you just need to change this mapping if you want to remap the keys. Something like:

    enum class Keys
    {
        TopLeft,
        TopRight,
        BottomLeft,
        BottomRight
    }
    QMap<Keys, HERE_METHOD_POINTER> mapping;
    connect (this, &MyClass::keypadTopLeft, [this]() { mapping[Keys::TopLeft](); });
    ...
    connect (this, &MyClass::keypadBottomRight, [this]() { mapping[Keys::BottomRight](); });
    
    J Offline
    J Offline
    JeKK666
    wrote on 29 Jun 2021, 12:54 last edited by
    #3

    @jsulm :O i did not know of QMap, will give it i try, thanks! :)

    Still haven't learned Lambdas...

    1 Reply Last reply
    0
    • J jsulm
      29 Jun 2021, 12:43

      @JeKK666 Why don't you use a mapping between key and method pointer? Then you just need to change this mapping if you want to remap the keys. Something like:

      enum class Keys
      {
          TopLeft,
          TopRight,
          BottomLeft,
          BottomRight
      }
      QMap<Keys, HERE_METHOD_POINTER> mapping;
      connect (this, &MyClass::keypadTopLeft, [this]() { mapping[Keys::TopLeft](); });
      ...
      connect (this, &MyClass::keypadBottomRight, [this]() { mapping[Keys::BottomRight](); });
      
      J Offline
      J Offline
      JeKK666
      wrote on 29 Jun 2021, 16:26 last edited by
      #4

      @jsulm It would seem i am not able to declare a QMap which uses a pointer to a method as the T value, as in QMap<Key, T>.

      I also have troubles reading your code:

      • i don't understand what results putting curly braces within connect() is going to produce;
      • i don't get what the square brackets around [this] mean;
      • i fail to grasp this overload of connect(), which is not the standard connect(senderObject, SIGNAL(sig()), receiverObject, SLOT(on_sig()))
        Could you elaborate more?

      Still haven't learned Lambdas...

      J J 2 Replies Last reply 29 Jun 2021, 18:55
      0
      • J JeKK666
        29 Jun 2021, 16:26

        @jsulm It would seem i am not able to declare a QMap which uses a pointer to a method as the T value, as in QMap<Key, T>.

        I also have troubles reading your code:

        • i don't understand what results putting curly braces within connect() is going to produce;
        • i don't get what the square brackets around [this] mean;
        • i fail to grasp this overload of connect(), which is not the standard connect(senderObject, SIGNAL(sig()), receiverObject, SLOT(on_sig()))
          Could you elaborate more?
        J Online
        J Online
        JonB
        wrote on 29 Jun 2021, 18:55 last edited by JonB
        #5

        @JeKK666
        All your questions are covered by New Signal Slot Syntax. Change over from old SIGNAL/SLOT() macros, and learn what a C++ lambda is (search that page for examples).

        1 Reply Last reply
        1
        • J JeKK666
          29 Jun 2021, 16:26

          @jsulm It would seem i am not able to declare a QMap which uses a pointer to a method as the T value, as in QMap<Key, T>.

          I also have troubles reading your code:

          • i don't understand what results putting curly braces within connect() is going to produce;
          • i don't get what the square brackets around [this] mean;
          • i fail to grasp this overload of connect(), which is not the standard connect(senderObject, SIGNAL(sig()), receiverObject, SLOT(on_sig()))
            Could you elaborate more?
          J Offline
          J Offline
          jsulm
          Lifetime Qt Champion
          wrote on 30 Jun 2021, 04:48 last edited by
          #6

          @JeKK666 said in Is it possible to mimic the functionality of an array of signals?:

          i don't understand what results putting curly braces within connect() is going to produce;
          i don't get what the square brackets around [this] mean;

          Please read about lambdas in C++.

          enum class Keys
          {
              TopLeft,
              TopRight,
              BottomLeft,
              BottomRight
          }
          typedef void (MyClass::*MethodPointer)();
          QMap<Keys, MethodPointer> mapping; // I assume mapping is class member
          connect (this, &MyClass::keypadTopLeft, [this]() { (this->*mapping[Keys::TopLeft])(); });
          ...
          connect (this, &MyClass::keypadBottomRight, [this]() { (this->*mapping[Keys::BottomRight])(); });
          

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          1
          • J Offline
            J Offline
            JeKK666
            wrote on 30 Jun 2021, 08:33 last edited by
            #7

            @JonB I wanted to retain the signal/slot model, since conceptually i connect the keypad to different Widgets, and each widget has a dedicated slot for the keypad signal to be connected to it; also, it is how this old software, tried and true, born with Qt4.8 is structured, so since it technically ain't broke, i am not going to fix it :P (code was subsequently ported to Qt 5.3.2, but never rewritten to use newer constructs).

            @jsulm I always had trouble grasping how lambdas work, therefore i never used them and a can't recognize them at a glance; i followed your suggestions, and smashed my head on it a little bit longer, i think i now have a better understading.

            The QMap was still giving me troubles until i read @jsulm's first answer, as i was not able to figure out the syntax i had to use for as a member function pointer.
            It did, however, provide me a suggestion on how to manually implement a similar strategy, resorting to a more basic approach: since a matrix of signals is not available, i created a matrix of function pointers called keypadMapper, where each function is a stupid wrapper for a call to emit signal(); .

            This gives me the code readability that i want while also avoiding code duplication for the connect-disconnect section in the main program:
            in the keypad class, after decoding the button, i will call

            (this->*keypadMapper[TOP_LEFT][KP_MAP_TYPE])(); 
            

            It might not be the most elegant solution, but it fits into the rest of the codebase with minimal effort on the rest of the classes, and to me also looks quite easy to read, which is a plus for maintainability.

            Thanks!

            Still haven't learned Lambdas...

            V 1 Reply Last reply 30 Jun 2021, 08:53
            1
            • J JeKK666
              30 Jun 2021, 08:33

              @JonB I wanted to retain the signal/slot model, since conceptually i connect the keypad to different Widgets, and each widget has a dedicated slot for the keypad signal to be connected to it; also, it is how this old software, tried and true, born with Qt4.8 is structured, so since it technically ain't broke, i am not going to fix it :P (code was subsequently ported to Qt 5.3.2, but never rewritten to use newer constructs).

              @jsulm I always had trouble grasping how lambdas work, therefore i never used them and a can't recognize them at a glance; i followed your suggestions, and smashed my head on it a little bit longer, i think i now have a better understading.

              The QMap was still giving me troubles until i read @jsulm's first answer, as i was not able to figure out the syntax i had to use for as a member function pointer.
              It did, however, provide me a suggestion on how to manually implement a similar strategy, resorting to a more basic approach: since a matrix of signals is not available, i created a matrix of function pointers called keypadMapper, where each function is a stupid wrapper for a call to emit signal(); .

              This gives me the code readability that i want while also avoiding code duplication for the connect-disconnect section in the main program:
              in the keypad class, after decoding the button, i will call

              (this->*keypadMapper[TOP_LEFT][KP_MAP_TYPE])(); 
              

              It might not be the most elegant solution, but it fits into the rest of the codebase with minimal effort on the rest of the classes, and to me also looks quite easy to read, which is a plus for maintainability.

              Thanks!

              V Offline
              V Offline
              VRonin
              wrote on 30 Jun 2021, 08:53 last edited by
              #8

              @JeKK666 said in Is it possible to mimic the functionality of an array of signals?:

              where each function is a stupid wrapper for a call to emit signal();.

              You don't need that. emit is meaningless to the compiler, it's just for readability. Just create a pointer to the signal directly. A signal is not magic, it's a public member. The only special feature is that it's body is not written by you but by moc

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              J 1 Reply Last reply 30 Jun 2021, 09:36
              3
              • V VRonin
                30 Jun 2021, 08:53

                @JeKK666 said in Is it possible to mimic the functionality of an array of signals?:

                where each function is a stupid wrapper for a call to emit signal();.

                You don't need that. emit is meaningless to the compiler, it's just for readability. Just create a pointer to the signal directly. A signal is not magic, it's a public member. The only special feature is that it's body is not written by you but by moc

                J Offline
                J Offline
                JeKK666
                wrote on 30 Jun 2021, 09:36 last edited by
                #9

                @VRonin I tried that several times over already (inspired from this): i based my assumptions on the fact that the declaration of a signal is syntactically identical to the declaration of a function prototype, save for the signals: keyword prepended to it, so i proceded to try and use a function pointer when passing arguments to the connect().

                Alas, i was never able to guess the correct syntax which would allow the darn thing to compile, i remember getting compile errors on the connect(), but could not reproduce now.
                Also, that would still require me to write switch-case connects based on the currently selected keypad map, or at least switch-case assignment of the signal pointer, since when i emit the signal, it still wouldn't accept array indexing (even more: decltype<...> threw at me all sorts of error, and i would also need a pointer for each signal)

                Still haven't learned Lambdas...

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  J.Hilk
                  Moderators
                  wrote on 30 Jun 2021, 10:36 last edited by
                  #10

                  @JeKK666

                  QMetaObject for the rescue:

                  #include <array>
                  
                  class SomeClass : public QObject
                  {
                      Q_OBJECT
                  
                      std::array<const char*, 3>  arrayOfSignals{"signal1", "signal2", "signal3"};
                      std::array<const char*, 3>  arrayOfSlots{"slot1", "slot2", "slot3"};
                  
                  public:
                      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() << "Call slots via signal array";
                          for(auto entry : arrayOfSignals){
                              QMetaObject::invokeMethod(this, entry);
                          }
                  
                          qDebug() << "Call Slots vis slot array";
                          for(auto entry : arrayOfSlots){
                              QMetaObject::invokeMethod(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;}
                  };
                  

                  does this do, what you want it to?


                  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.

                  J 1 Reply Last reply 5 Jul 2021, 07:32
                  1
                  • J J.Hilk
                    30 Jun 2021, 10:36

                    @JeKK666

                    QMetaObject for the rescue:

                    #include <array>
                    
                    class SomeClass : public QObject
                    {
                        Q_OBJECT
                    
                        std::array<const char*, 3>  arrayOfSignals{"signal1", "signal2", "signal3"};
                        std::array<const char*, 3>  arrayOfSlots{"slot1", "slot2", "slot3"};
                    
                    public:
                        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() << "Call slots via signal array";
                            for(auto entry : arrayOfSignals){
                                QMetaObject::invokeMethod(this, entry);
                            }
                    
                            qDebug() << "Call Slots vis slot array";
                            for(auto entry : arrayOfSlots){
                                QMetaObject::invokeMethod(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;}
                    };
                    

                    does this do, what you want it to?

                    J Offline
                    J Offline
                    JeKK666
                    wrote on 5 Jul 2021, 07:32 last edited by JeKK666 7 May 2021, 07:46
                    #11

                    @J-Hilk Yes! I had also tried using the QMetaObject::invokeMethod(), but never got around to make it work: no compile time errors, just no execution of the slot whatsoever, and was never able to narrow it down to either signal emission or sig/slot connection...

                    Anyhow, call me dumb but i find the syntax for this overall thing a lot more convoluted than a matrix of function pointers >.<'
                    Still, a much more elegant solution nonetheless, that's great.

                    Thanks!

                    Still haven't learned Lambdas...

                    J 1 Reply Last reply 5 Jul 2021, 08:06
                    1
                    • J JeKK666
                      5 Jul 2021, 07:32

                      @J-Hilk Yes! I had also tried using the QMetaObject::invokeMethod(), but never got around to make it work: no compile time errors, just no execution of the slot whatsoever, and was never able to narrow it down to either signal emission or sig/slot connection...

                      Anyhow, call me dumb but i find the syntax for this overall thing a lot more convoluted than a matrix of function pointers >.<'
                      Still, a much more elegant solution nonetheless, that's great.

                      Thanks!

                      J Offline
                      J Offline
                      J.Hilk
                      Moderators
                      wrote on 5 Jul 2021, 08:06 last edited by
                      #12

                      @JeKK666 said in Is it possible to mimic the functionality of an array of signals?:

                      Anyhow, call me dumb but i find the syntax for this overall thing a lot more convoluted than a matrix of function pointers >.<'

                      I would say, thats a debatable point :D

                      #include <array>
                      
                      class SomeClass : public QObject
                      {
                          typedef void (SomeClass::*SomeClassFunction)();
                          Q_OBJECT
                      
                      //    std::array<const char*, 3>  arrayOfSignals{"signal1", "signal2", "signal3"};
                      //    std::array<const char*, 3>  arrayOfSlots{"slot1", "slot2", "slot3"};
                      
                              std::array<SomeClassFunction,3> arrayOfSignalsPointers{&SomeClass::signal1,&SomeClass::signal2, &SomeClass::signal3};
                              std::array<SomeClassFunction, 3> arrayOfSlotsPointers{&SomeClass::slot1, &SomeClass::slot2, &SomeClass::slot3};
                      
                      public:
                          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() << "Call slots via signal array";
                      //        for(auto entry : arrayOfSignals){
                      //            QMetaObject::invokeMethod(this, entry);
                      //        }
                      
                      //        qDebug() << "Call Slots vis slot array";
                      //        for(auto entry : arrayOfSlots){
                      //            QMetaObject::invokeMethod(this, entry);
                      //        }
                      
                              //----
                              for(auto entry : arrayOfSignalsPointers){
                                  (this->*entry)();
                              }
                      
                              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.

                      1 Reply Last reply
                      0

                      12/12

                      5 Jul 2021, 08:06

                      • Login

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