Подключение сигналов к слотам с меньшим количеством параметров, разрешенных в Qt?

допустимо ли вызывать

QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot()));

без параметров? Кажется, что это работает (без исключения во время выполнения), но я не могу найти ссылку в документах. Все я нашел, что это возможно, если someslot есть параметр по умолчанию. Это действительно в данном случае. Но мой метод someslot имеет не тот же параметр, что и по умолчанию (здесь в примере нет параметра).

таким образом, кажется возможным передавать сигналы в слоты с меньшими параметрами?

2 ответов


Да, все в порядке. Есть короткое предложение об этом в Сигналы И Слоты документы:

[...] Сигнатура сигнала должна соответствовать сигнатуре приемного слота. (фактически слот может иметь более короткую сигнатуру чем сигнал который он получает, поскольку он может игнорировать дополнительные аргументы.) [...]

есть даже такой пример, как это дальше по странице, где объясняются аргументы по умолчанию.


С точки зрения стандартного C++ решение Qt также работает.

испускание сигнала осуществляется путем вызова метода:

emit someSignal(3.14);

на emit ключевое слово фактически разрешается в пустое #define, поэтому строка выше просто вызывает метод someSignal с приведенными аргументами. Метод, возможно, был объявлен внутри QObject-производного класса, например:

class SomeObject: public QObject {
    Q_OBJECT
public slots:
    void firstSlot() { /* implementation */ }
    void secondSlot(double) {  /* implementation */ }

signals:
    void someSignal(double);  /* no implementation here */
};

это должно показаться вам знакомым, но вы могли бы задаться вопросом, где фактический реализация ваших сигналов происходит от. Как вы можете догадаться, именно здесь запускается компилятор meta object compiler (MOC) Qt. Для каждого метода объявил внутри signals раздел он предоставляет в своем сгенерированном источнике реализация это примерно выглядит так:

void SomeObject::someSignal(double _t1)
{
    void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
}

интересная часть является void *_a[] вектор, который заполняется указателями на аргументы, переданные сигналу. Ничего особенного.

аргумент вектор передается в QMetaObject::activate, который, в свою очередь, выполняет некоторые проверки безопасности потоков и другую уборку, а затем начинает вызывать слоты, которые были подключены к сигналу, если таковые имеются. Поскольку соединения сигнал-слот разрешаются во время выполнения (так, что connect() works), небольшая помощь от MOC требуется снова. В частности, MOC также генерирует qt_static_metacall() реализация класса:

void SomeObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        SomeObject *_t = static_cast<SomeObject *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->firstSlot(); break;
        case 1: _t->secondSlot((*reinterpret_cast< double(*)>(_a[1]))); break;
        default: ;
        }
    } /* some more magic */
}

как вы можете видеть, этот метод содержит другой конец для разрешения void *_a[] вектор до вызова функции. Также вы можете видеть, что нет вариационного списка аргументов (используя многоточие,...) или другой сомнительный обман.

Итак, чтобы осветить первоначальный вопрос: когда, например someSignal(double) соединяется с secondSlot(double) что соответствует сигнатуре сигнала, вызов разрешает case 1 на qt_static_metacall и он просто передает аргумент, как ожидалось.

при подключении сигнала к firstSlot() что имеет меньше аргументов, чем сигнал, вызов разрешает case 0 и firstSlot() вызывается без аргументов. Аргумент, который был передан сигналу, просто остается нетронутым в его void *_a[] вектор.