模板参数推导无法与QT lambda

时间:2017-03-04 20:04:58

标签: c++ qt lambda template-deduction argument-deduction

我有一个QT 5.7&的项目。 Visual Studio 2015发出有关演绎规则的编译器错误。就演绎规则而言,我有点新手,所以我想看看是否有人可以告诉我如何解决这个问题,并解释到目前为止功能签名匹配的情况。

我正在尝试使用基于模板的智能连接器来管理我的QT项目中的信号和插槽。我从Stack Overflow中的this Q&A获得了这种信号/插槽管理方法的灵感。应该自动管理信号/插槽的模板代码如下:

//! 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成员用于跟踪信号/插槽,以便在应用程序关闭某些UI事件时这些成员可以自动断开连接。

我正在尝试连接的QT对象是QSerialPort。我试图将QSerialPort的'字节写'信号(从其QIODevice父继承)连接到lambda中的一个插槽,但它无法编译时出现以下错误:

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'

如果我尝试不使用lambdas(使用QT连接调用)这样做,它可以正常工作....

// Connect Tx/Rx handlers
connect(mPort.get(), &QSerialPort::bytesWritten, this, &MainWindow::processTx);

但是在mainwindow.cpp中调用QtConnect模板如下:

// Connect Tx/Rx handlers
QtConnect(mPort.get(), &QSerialPort::bytesWritten, [&](qint64 bytes) {
    ...
});

导致上述错误。 mPort是指针std::unique_ptr<QSerialPort>

bytesWritten信号继承自QSerialPort的父类QIODevice并具有签名void bytesWritten(qint64 bytes)

1 个答案:

答案 0 :(得分:1)

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,而不是pointerM*明确是pointer。这种矛盾使编译器无法解析模板。