У меня есть проект с QT 5.7 & Visual Studio 2015, которая выдает ошибку компилятора о правилах удержания. Я немного новичок в том, что касается правил дедукции, поэтому я хотел бы посмотреть, может ли кто-нибудь показать мне, как обойти это, а также объяснить, что происходит с сопоставлением сигнатур функций.
Я пытаюсь использовать умный соединитель на основе шаблонов для управления сигналами и слотами в моем проекте QT. Я получил вдохновение для этого подхода к управлению сигналами / слотами от этот вопрос& в переполнении стека. Код шаблона, который должен автоматически управлять сигналом / слотами, выглядит следующим образом:
//! see https://stackoverflow.com/questions/26553029/
//! how-to-disconnect-a-lambda-function-without-storing-connection.
using ListenToken = std::shared_ptr<void>;
struct Disconnecter {
QMetaObject::Connection mConnection;
explicit Disconnecter(QMetaObject::Connection&& conn)
: mConnection(std::move(conn))
{}
~Disconnecter() {
QObject::disconnect(mConnection);
}
};
template<class F, class T, class M>
ListenToken QtConnect(T* source, M* method, F&& f) {
return std::make_shared<Disconnecter>(
QObject::connect(source, method, std::forward<F>(f))
);
}
using SignalSlotInfo = std::vector<ListenToken>;
В моем классе главного окна у меня есть SignalSlotInfo
член, который я использую для отслеживания сигнала / слотов, чтобы они могли автоматически отключаться при закрытии приложения какого-либо события пользовательского интерфейса.
Рассматриваемый объект QT, который я пытаюсь подключить, — это QSerialPort. Я пытаюсь подключить сигнал QSerialPort «записано в байтах» (унаследованный от его QIODevice
parent) в слот в лямбде, но он не может скомпилировать следующую ошибку:
1>mainwindow.cpp(1246): error C2672: 'QtConnect': no matching overloaded function found
1>mainwindow.cpp(1246): error C2784: 'ListenToken QtConnect(T *,M *,F &&)': could not deduce template argument for 'M *' from 'void (__cdecl QIODevice::* )(qint64)'
1> c:\users\johnc\main\app739\app739\mainwindow.h(58): note: see declaration of 'QtConnect'
Если я попытаюсь сделать это без использования лямбда-выражений (используя вызовы QT-соединения), то это будет нормально работать ….
// Connect Tx/Rx handlers
connect(mPort.get(), &QSerialPort::bytesWritten, this, &MainWindow::processTx);
Однако, вызывая шаблон QtConnect в mainwindow.cpp следующим образом:
// Connect Tx/Rx handlers
QtConnect(mPort.get(), &QSerialPort::bytesWritten, [&](qint64 bytes) {
...
});
Результаты в ошибках, указанных выше. mPort
это указатель std::unique_ptr<QSerialPort>
bytesWritten
сигнал наследуется от родительского класса QSerialPort QIODevice и имеет подпись void bytesWritten(qint64 bytes)
замещать M*
от M
:
template<class F, class T, class M>
ListenToken QtConnect(T* source, M method, F&& f) {
return std::make_shared<Disconnecter>(
QObject::connect(source, method, std::forward<F>(f))
);
}
Причина этого в том, что если вы уйдете M*
компилятор попытается разрешить шаблон, имея M*
установлен в void (QIODevice::*)(qint64)
, тем не мение void (QIODevice::*)(qint64)
это pointer-to-member
не pointer
а также M*
явно pointer
, Это противоречие делает компилятор неспособным разрешить шаблон.
Других решений пока нет …