Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are Qt signals NOT const

Qt uses signals and slots for object communication. Signals are normally declared as a member function and the Qt MOC then generates the definition of that function.

What I would like to understand is why signals are not const member functions?

Edit: I would expect signals not to modify the sender, that's why the question.

like image 786
Mac Avatar asked Sep 01 '16 22:09

Mac


People also ask

How do signals work in Qt?

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.

Can a Qt signal return a value?

The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals. So: according to the docs, this thing isn't possible.


2 Answers

I would expect signals not to modify the sender

Signals (as generated by the MOC) do not directly modify a class instance' members. The generated code, however, passes a this pointer along, for consumption by a (potential) slot. A connected slot could thus mutate the sender of the signal.

So the technical reason is, that if signals were const, it would require that all slot implementations would only call const class members on the sender for the code to compile without errors.

Implementing signals as non-const class members is an understandable decision, with respect to code safety. It still feels unnatural in a number of cases (e.g. if the connected slot implemented in the same class is const, or if the connected slot belongs to another object altogether).

like image 172
IInspectable Avatar answered Oct 11 '22 01:10

IInspectable


Nothing prevents a Qt signal to be const AFAIK (tested with Qt5.9). The answer from IInspectable is not correct.

Below is a test I made to show it is still possible to
- connect a const signal to a non-const slot in the same instance
- call non-const methods on the sender().

The class of my test, which compiles fine (gcc) :

// Stupid class to test the emit of a const-signal
class Test : public QObject
{
    Q_OBJECT

public:
    // Connect in the constructor from this instance to this instance
    explicit Test(QObject *parent = nullptr) : QObject(parent) {
        connect(this, &Test::valueChanged, this, &Test::updateString);
    }

    // To test a non-const method call
    void nonConstFoo() {
        setObjectName("foo"); // I modify the 'this' instance
    }

    // To test emit of a non-const signal from a const-method
//    void constFoo() const {
//        emit fooSignal(); // --> FAIL at compile time
//    }

public slots:
    void setValue(int value) {
        m_value = value;
        emit valueChanged(value);
    }

    void updateString(int value) {
        m_string = QString::number(value); // I modify the 'this' instance
        nonConstFoo(); // I modify the 'this' instance through a non-const call

        auto s = sender();
        s->setObjectName("mutated name"); // I modify the 'sender' instance

        qDebug() << "Updated string" << m_string;
    }

signals:
    void valueChanged(int) const; // The signal is const
    void fooSignal(); // Non-const signal

private:
    int m_value;
    QString m_string;
};

And here is the code generated by the MOC for the signals :

// SIGNAL 0
void Test::valueChanged(int _t1)const
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(const_cast< Test *>(this), &staticMetaObject, 0, _a);
}

// SIGNAL 1
void Test::fooSignal()
{
    QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}

We can see that Qt uses const_cast on this so everything will work anyway.


In my opinion, the reason the signals are not const by default is that this would require the MOC to add a const to your signal (== class-method) definition in your header, therefore modify your source code.

I guess this would be doable by enclosing each definition of signal in a macro, but imagine the pain for the coder and for the reader. I do not see any gain for Qt (nor you) that you have your signals declared as const, and this would require more work for you and Qt.

But you may need to declare them as const sometimes. Like when you want to emit them from a const method. And you are free to do so.

like image 9
ymoreau Avatar answered Oct 10 '22 23:10

ymoreau