Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Private slots

Private slots

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 2 Posters 2.2k 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.
  • kshegunovK Offline
    kshegunovK Offline
    kshegunov
    Moderators
    wrote on last edited by
    #1

    Hi,
    I have been able to make use of "truly" private slots through the pointer to member syntax with lambdas. However, it starts to clutter unrelated parts of my code, which I would want to avoid. Consider for example this constructor:

    AedWoodsSaxonOperator::AedWoodsSaxonOperator(QObject * parent)
        : AedOperator(new AedWoodsSaxonOperatorPrivate(this), parent)
    {
        Q_D(AedWoodsSaxonOperator);
    
        auto onNucleusChange = [this, d] (AedNucleus * nucleus) -> void {
            QObject::disconnect(d->nucleonsChanged);
            d->nucleonsChanged = QObject::connect(nucleus, &AedNucleus::nucleonsChanged, [this, d] (quint16 nucleons) -> void {
                d->radius = 1.25 * std::cbrt(nucleons);
            });
        };
    
        QObject::connect(this, &AedOperator::modelChanged, this, [this, d, onNucleusChange] (AedModel * model) -> void {
            onNucleusChange(model->nucleus());
    
            QObject::disconnect(d->nucleusChanged);
            d->nucleusChanged = QObject::connect(model, &AedModel::nucleusChanged, this, onNucleusChange);
        });
    }
    

    It contains code that's completely unrelated to initialization and I'd love to move it out of there (ideally I'd place it in the private class). So what are my options? Am I stuck to Q_PRIVATE_SLOT and the old syntax?

    Thanks in advance.

    Read and abide by the Qt Code of Conduct

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #4

      Ok, now I get it (or at least I think I do).

      you can use the method of the private class the same way you use a lambda (lambda is just a special case of the more general std::function call):

      testprivate.h

      #include <QObject>
      class TestCallSlotPrivate;
      class TestCallSlot : public QObject
      {
          Q_OBJECT
          Q_DECLARE_PRIVATE(TestCallSlot)
          Q_DISABLE_COPY(TestCallSlot)
      public:
          explicit TestCallSlot(QObject* parent = Q_NULLPTR);
          virtual ~TestCallSlot();
      protected:
          TestCallSlotPrivate* d_ptr;
      };
      

      testprivate.cpp

      #include "testprivate.h"
      #include <QTimer>
      #include <functional>
      class TestCallSlotPrivate{
          Q_DECLARE_PUBLIC(TestCallSlot)
          TestCallSlotPrivate(TestCallSlot* q)
              :q_ptr(q)
          {
              Q_ASSERT(q);
              QObject::connect(&m_privateTimer,&QTimer::timeout,q/*just gives context*/,std::bind(&TestCallSlotPrivate::privateSlot,this));
              m_privateTimer.start(300);
          }
      
          TestCallSlot* q_ptr;
          QTimer m_privateTimer;
          void privateSlot(){
              qDebug("Slot Called");
          }
      };
      
      
      
      TestCallSlot::TestCallSlot(QObject *parent)
          : QObject(parent)
          , d_ptr(new TestCallSlotPrivate(this))
      {
      }
      
      TestCallSlot::~TestCallSlot(){
          delete d_ptr;
      }
      

      "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

      1 Reply Last reply
      2
      • VRoninV Offline
        VRoninV Offline
        VRonin
        wrote on last edited by
        #2

        Probably I got this question completely wrong but Q_DECLARE_PUBLIC(x) contains friend class x; so from the private part can't you access the private slot directly through the q pointer?

        "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

        kshegunovK 1 Reply Last reply
        0
        • VRoninV VRonin

          Probably I got this question completely wrong but Q_DECLARE_PUBLIC(x) contains friend class x; so from the private part can't you access the private slot directly through the q pointer?

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #3

          I think you misunderstand me. I mean the following:
          I'd like to move this code into functions/slots inside the private class, not vice versa (it already is in the public class); the problem isn't accessing the public class from the private one. So currently I can attach lambdas but if I go with Q_PRIVATE_SLOT I'm stuck with the old connect syntax (as the private class isn't a QObject derived). Perhaps I'm missing something, hence the question ...

          Read and abide by the Qt Code of Conduct

          1 Reply Last reply
          0
          • VRoninV Offline
            VRoninV Offline
            VRonin
            wrote on last edited by VRonin
            #4

            Ok, now I get it (or at least I think I do).

            you can use the method of the private class the same way you use a lambda (lambda is just a special case of the more general std::function call):

            testprivate.h

            #include <QObject>
            class TestCallSlotPrivate;
            class TestCallSlot : public QObject
            {
                Q_OBJECT
                Q_DECLARE_PRIVATE(TestCallSlot)
                Q_DISABLE_COPY(TestCallSlot)
            public:
                explicit TestCallSlot(QObject* parent = Q_NULLPTR);
                virtual ~TestCallSlot();
            protected:
                TestCallSlotPrivate* d_ptr;
            };
            

            testprivate.cpp

            #include "testprivate.h"
            #include <QTimer>
            #include <functional>
            class TestCallSlotPrivate{
                Q_DECLARE_PUBLIC(TestCallSlot)
                TestCallSlotPrivate(TestCallSlot* q)
                    :q_ptr(q)
                {
                    Q_ASSERT(q);
                    QObject::connect(&m_privateTimer,&QTimer::timeout,q/*just gives context*/,std::bind(&TestCallSlotPrivate::privateSlot,this));
                    m_privateTimer.start(300);
                }
            
                TestCallSlot* q_ptr;
                QTimer m_privateTimer;
                void privateSlot(){
                    qDebug("Slot Called");
                }
            };
            
            
            
            TestCallSlot::TestCallSlot(QObject *parent)
                : QObject(parent)
                , d_ptr(new TestCallSlotPrivate(this))
            {
            }
            
            TestCallSlot::~TestCallSlot(){
                delete d_ptr;
            }
            

            "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

            1 Reply Last reply
            2
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #5

              In your case:

              AedWoodsSaxonOperator::AedWoodsSaxonOperator(QObject * parent)
                  : AedOperator(new AedWoodsSaxonOperatorPrivate(this), parent)
              {
                  Q_D(AedWoodsSaxonOperator);
              
              
                  QObject::connect(this, &AedOperator::modelChanged, this, std::bind(&AedWoodsSaxonOperatorPrivate::onModelChanged,d,std::placeholders::_1));
              }
              
              void AedWoodsSaxonOperatorPrivate::onNucleusChange(AedNucleus * nucleus){
              QObject::disconnect(nucleonsChanged);
              nucleonsChanged = QObject::connect(nucleus, &AedNucleus::nucleonsChanged, q_func(), std::bind(&AedWoodsSaxonOperatorPrivate::onNucleonsChanged,this,std::placeholders::_1));
              }
              
              void AedWoodsSaxonOperatorPrivate::onNucleonsChanged(quint16 nucleons){
              radius = 1.25 * std::cbrt(nucleons);
              }
              
              void AedWoodsSaxonOperatorPrivate::onModelChanged(AedModel * model){
              onNucleusChange(model->nucleus());
              QObject::disconnect(nucleusChanged);
              nucleusChanged = QObject::connect(model, &AedModel::nucleusChanged, q_func(), std::bind(&AedWoodsSaxonOperatorPrivate::onNucleusChange,this,std::placeholders::_1));
              }
              

              "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

              1 Reply Last reply
              2
              • kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by
                #6

                Well I am a dumb ass! This should work fine. Thanks, Luca!

                Read and abide by the Qt Code of Conduct

                VRoninV 1 Reply Last reply
                0
                • kshegunovK kshegunov

                  Well I am a dumb ass! This should work fine. Thanks, Luca!

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #7

                  @kshegunov said in Private slots:

                  Well I am a dumb ass!

                  You most definitely are not.

                  Final question. Did you end up using std::bind or did you manage to find a way to use pre-C++11 function pointers in this case?

                  "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

                  kshegunovK 1 Reply Last reply
                  0
                  • VRoninV VRonin

                    @kshegunov said in Private slots:

                    Well I am a dumb ass!

                    You most definitely are not.

                    Final question. Did you end up using std::bind or did you manage to find a way to use pre-C++11 function pointers in this case?

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #8

                    @VRonin said in Private slots:

                    Did you end up using std::bind or did you manage to find a way to use pre-C++11 function pointers in this case?

                    Yes, I used std::bind. If I'm not mistaken it creates a wrapper call around the function pointer, right. So:

                    std::bind(&AedWoodsSaxonOperatorPrivate::onModelChanged,d,std::placeholders::_1)
                    

                    Would expand to something like:

                    void (AedWoodsSaxonOperatorPrivate::*ptm)(AedModel *) = &AedWoodsSaxonOperatorPrivate::onModelChanged;
                    [d, ptm] (AedModel * model) -> void {
                        (d->*ptm)(model);
                    }
                    

                    Not that I can't do it manually, but I see no reason to bother with it. I use pre-C++11 pointer to member trickery in another place:

                    class AedWoodsSaxonOperatorPrivate : public AedOperatorPrivate
                    {
                        Q_DECLARE_PUBLIC(AedWoodsSaxonOperator)
                    
                        typedef qreal (AedWoodsSaxonOperatorPrivate::*OneBodyMatrixElement)(qint32, qint32);
                    
                    public:
                        // Definition is not provided and will never be. Just a forward declaration for the specializations.
                        template <class Basis>
                        qreal matrixElement(qint32, qint32);
                    
                    protected:
                        OneBodyMatrixElement oneBodyMatrixElement;
                    };
                    

                    Where that one is set like this:

                    void AedWoodsSaxonOperatorPrivate::basisChanged(AedBasis * basis)
                    {
                        if (dynamic_cast<AedCylindricalBasis *>(basis))
                            oneBodyMatrixElement = &AedWoodsSaxonOperatorPrivate::matrixElement<AedCylindricalBasis>;
                        else
                            oneBodyMatrixElement = nullptr;
                    }
                    

                    This is relevant only for the private API (naturally) and the rationale is to forgo a second level of polymorphism and spare myself a virtual call, hopefully improving branch prediction. This one actually matters as it's called millions of times while for the one from the question above I don't care about any efficiency, it's called a handful of times.

                    PS.
                    If you're curious, current code can be found here

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    2

                    • Login

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