最方便的方法可能是创建一个模板,实现与常规 QObject::connect
调用相同的语法。
我使用 Stefan Monov 的答案制作了以下两个模板。第一个基于方法指针,第二个基于 Lambda 表达式。
#ifndef CONNECT_ONCE_H
# define CONNECT_ONCE_H
# include <QObject>
# include <memory>
template<typename EMITTER, typename SIGNAL, typename RECEIVER, typename... ARGS>
void connectOnce(EMITTER* emitter, SIGNAL signal, RECEIVER* receiver, void (RECEIVER::*slot)(ARGS...), Qt::ConnectionType connectionType = Qt::AutoConnection)
{
auto connection = std::make_shared<QMetaObject::Connection>();
auto onTriggered = [connection, receiver, slot](ARGS... arguments){
(receiver->*slot)(arguments...);
QObject::disconnect(*connection);
};
*connection = QObject::connect(emitter, signal, receiver, onTriggered, connectionType);
}
template<typename EMITTER, typename SIGNAL, typename RECEIVER, typename SLOT, typename... ARGS>
void connectOnce(EMITTER* emitter, SIGNAL signal, RECEIVER* receiver, SLOT slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
{
std::function<void (ARGS...)> callback = slot;
auto connection = std::make_shared<QMetaObject::Connection>();
auto onTriggered = [connection, callback](ARGS... arguments) {
callback(arguments...);
QObject::disconnect(*connection);
};
*connection = QObject::connect(emitter, signal, receiver, onTriggered, connectionType);
}
#endif
关于基于 lambda 的模板,当我直接声明
std::function
作为参数时,我无法将其编译,因为编译器无法将 lambda 参数识别为有效的候选项...这就是为什么我将
SLOT
声明为模板参数,然后将其转换为
std::function
。虽然不像我想象的那样简洁,但它能够工作。
disconnect()
真是个问题啊? - folibishandleSig
名称被复制了三次,2. 阅读起来更困难,3. 无法在connect
调用内定义处理程序。 - Stefan Monov