It would probably most convenient to make a template implementing the same syntax as a regular QObject::connect
call.
I've made these two templates below, using Stefan Monov's own answer. The first is method pointer based, the second one is lambda based.
#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
About the lambda based template, I couldn't get it to compile when directly declaring std::function
as a parameter, as the compiler couldn't recognize a lambda parameter as a valid candidate... which is why I'm declaring SLOT
as a template parameter, and then casting it to std::function
. It's not as concise as I would've liked, but it works.
disconnect()
? – ExcurvatehandleSig
name is triplicated, 2. It's harder to read, and 3. Can't define the handler inside theconnect
call. – Joacima