У меня есть класс, который имеет сигнал с этой подписью:

// CLASS A
signals:
    void requestToChangeRange(voltage_range_e vr, current_range_e cr, uint16_t bits);

Есть другой класс, у которого есть слот, подобный этому (обратите внимание на дополнительный параметр)

// CLASS C
public slots:
    void handleRequestRangeChange(voltage_range_e vr, current_range_e cr, uint16_t bits, uint16_t limiter);

Тогда у меня есть класс "B", который служит местом встречи всех других классов. Когда класс «A» излучает сигнал, класс «C» должен перенаправить его в класс «B». Но этот дополнительный аргумент в слоте класса «B» является проблемой, потому что этот дополнительный аргумент исходит от другого класса «X».

Поэтому, если бы сигнал и слоты классов «А» и «С» совпадали, я бы сделал следующее в классе «В»:

// somewhere in CLASS B (the manager of all other classes)
connect(pClassA, &ClassA::requestToChangeRange,
    pClassC, &ClassC::handleRequestRangeChange);

Но очевидно, что это не работает из-за сигнатур функций. Что я хочу сделать, это что-то вроде:

// somewhere in CLASS B (the manager of all other classes)
connect(pClassA, &ClassA::requestToChangeRange,
this /* class B */, []() {
    // Get that last required parameter from class X
    uint16_t limiter = pClassX->getValue();
    // Call slot of class C
    pClassC->handleRequestRangeChange(vr, cr, bits, limiter);
});

Так как же я могу получить доступ к этим переданным параметрам внутри лямбды? Это вообще возможно?

4
DEKKER 17 Апр 2019 в 12:08

2 ответа

Лучший ответ

Ваша лямбда должна знать оба объекта: [pClassX, pClassC] и принимать исходные параметры сигнала: (voltage_range_e vr, current_range_e cr, uint16_t bits).

Так что ваше соединение должно начаться так:

connect(pClassA, &ClassA::requestToChangeRange, this,
    [pClassX, pClassC](voltage_range_e vr, current_range_e cr, uint16_t bits) {
    //...
});

О «получателе» в операторе connect ():

Этот указатель на QObject на самом деле не нужен при подключении к лямбде, но он служит для того, чтобы соединение сигнального слота было удалено, если отправитель или получатель будут уничтожены.

Использование this означает, что вы должны убедиться, что после удаления любого из pClassX, pClassC вы больше не будете излучать сигнал. В качестве альтернативы вы можете использовать pClassC в качестве получателя, тогда вы должны быть уверены, что pClassX остается в силе, пока pClassC и pClassA живы ... В идеале вы должны указать pClassX И pClassC как получатели, но это невозможно. Для этого вы можете использовать защитные функции QPointer.

5
Martin Hennings 17 Апр 2019 в 09:19

В этом контексте стоит упомянуть одну хитрость: если вы захватываете указатели на объекты QObject, я бы порекомендовал сначала создать переменные QPointer и использовать THOSE в лямбда-выражении. Таким образом, вы можете проверить, были ли они удалены. Если вы используете нормальный сигнал и слоты, об этом позаботятся, но с лямбдами вам, возможно, придется обрабатывать ссылки на всю жизнь.

Надеюсь, скоро мы получим более удобные способы захвата C ++ с помощью созданных объектов.

1
Allan Jensen 24 Апр 2019 в 12:39