需求

qt 在使用 connect 连接时,有些时候因为类型匹配的问题,会报错:

QPushButton * controller_button_[APP_NUM_OF_CONTROLLER];
QSignalMapper * signalMapper_;

signalMapper_ = new QSignalMapper(this);
for (int i = 0; i < APP_NUM_OF_CONTROLLER; i++) {
    controller_button_[i] = new QPushButton(this);
    connect(controller_button_[i], &QPushButton::clicked, signalMapper_, &QSignalMapper::map);

    signalMapper_->setMapping(controller_button_[i], i);
}

connect(signalMapper_, &QSignalMapper::mapped, this, &MainWindow::ClickDetail);
mainwindow.cpp:173:9: error: no matching member function for call to 'connect'
qobject.h:222:36: note: candidate function not viable: no known conversion from 'void (QAbstractButton::*)(bool) __attribute__((thiscall))' to 'const char *' for 2nd argument
qobject.h:225:36: note: candidate function not viable: no known conversion from 'void (QAbstractButton::*)(bool) __attribute__((thiscall))' to 'const QMetaMethod' for 2nd argument
qobject.h:481:41: note: candidate function not viable: no known conversion from 'void (QAbstractButton::*)(bool) __attribute__((thiscall))' to 'const char *' for 2nd argument
qobject.h:242:43: note: candidate template ignored: couldn't infer template argument 'Func2'
qobject.h:283:13: note: candidate template ignored: couldn't infer template argument 'Func2'
qobject.h:322:13: note: candidate template ignored: couldn't infer template argument 'Func2'
qobject.h:274:13: note: candidate function template not viable: requires 3 arguments, but 4 were provided
qobject.h:314:13: note: candidate function template not viable: requires 3 arguments, but 4 were provided

虽然可以使用 SIGNAL(), SLOT() 这样,qt4 旧的 style 来写,但是还是希望能够使用 qt5 新 style 写。

connect(controller_button_[i], SIGNAL(clicked()), signalMapper_, SLOT(map()));
connect(signalMapper_, SIGNAL(mapped(int)), this, SLOT(ClickDetail(int)));

解决

其实报错的时候,已经说的很清楚了,就是类型的问题。首先需要核对信号函数的类型和槽函数的类型,然后才能决定后面怎么来写。

void clicked(bool checked = false);

void map();
void map(QObject *sender);

void mapped(int);
void mapped(const QString &);
void mapped(QWidget *);
void mapped(QObject *);

void MainWindow::ClickDetail(int id);

信号和槽能匹配类型

可以看到上面的 mapped 其中一种是可以和 ClickDetial 类型匹配的,所以我们只需要明确指出具体是哪种类型即可。 C++11 只能使用 QOverload, C++14 还可以使用 qOverload.

// c++11
connect(signalMapper_, QOverload<int>::of(&QSignalMapper::mapped), this, &MainWindow::ClickDetail);

// c++14
connect(signalMapper_, qOverload<int>(&QSignalMapper::mapped), this, &MainWindow::ClickDetail);

信号和槽不能匹配类型

clickedmap 没有一个能完全匹配,我们只能想其他方法,最简单的就是套壳再包装一层。我们可以使用 Lambda 表达式来达成目的。

connect(controller_button_[i], &QPushButton::clicked, signalMapper_, [=]() {signalMapper_->map();});

参考

no matching member function for call to ‘connect’ - simple example why doesn’t this work??

Selecting Overloaded Signals and Slots

QT信号槽报错no matching member function for call to ‘connect’