Here are two approaches to hide accounting problems.
Firstly, we support std::vector , which, when destroyed, disconnects us from the source:
typedef std::shared_ptr<void> listen_token; struct disconnecter { QMetaObject::Connection conn; disconnecter( QMetaObject::Connection&& c ):conn(std::move(c)) {} ~disconnecter() { QObject::disconnect(conn); } }; template<class F, class T, class M> listen_token QtConnect( T* source, M* method, F&& f ) { return std::make_shared<disconnecter>( QObject::connect( source, method, std::forward<F>(f)); ); } typedef std::vector<listen_token> connections;
Then we connect as follows:
connections conns; conns.emplace_back( QtConnect( bob, &Bob::mySignal, [](QString str){ std::cout << "Hello World!\n"; } ) );
when a vector is destroyed, connection objects are also destroyed.
This is similar to how other signal / slot systems are processed, where the listener tracks the token and then returns it. But here I save the disconnect object with an opaque type that clears the connection upon destruction.
Note that copying this vector will extend the lifetime of the connection. If the message is sent to a specific instance of the class, save the connections instance in the class and you will not receive the message after the instance is destroyed.
The second approach, based on what @lpapp discovered, is if you have a lambda that you want to call only once in response to a signal, then disable:
template<class F> struct auto_disconnect_t { F f; std::shared_ptr<QMetaObject::Connection> conn; template<class U> auto_disconnect_t(U&& u): f(std::forward<U>(u)), conn(std::make_shared<QMetaObject::Connection>()) {} template<class... Args> void operator()(Args&&... args)const{ QObject::disconnect(*conn); f( std::forward<Args>(args)... ); } }; template<class T, class M, class F> void one_shot_connect( T* t, M* m, F&& f ) { typedef typename std::decay<F>::type X; auto_disconnect_t<X> helper(std::forward<F>(f)); *helper.conn = QObject::connect( t, m, helper ); };
here we are one_shot_connect( bob, Bob::mySignal, [](QString str) { std::cout << "Hello\n" } ); , and the next time the signal is triggered, we get a message, and then the connection is disconnected.
I disconnect before processing the lambda, just in case the lambda causes the signal to light up or something like that.