这里有两种隐藏簿记问题的方法。
首先,我们维护一个std::vector,它在销毁时会断开我们与源的连接:
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;
然后我们连接如下:
connections conns;
conns.emplace_back( QtConnect( bob, &Bob::mySignal, [](QString str){ std::cout << "Hello World!\n"; } ) );
当向量被销毁时,连接对象也被销毁。
这类似于其他信号/槽系统的处理方式,侦听器跟踪令牌,然后返回它。但在这里,我将断开连接对象保留在不透明类型中,以便在销毁时清除连接。
请注意,复制该向量将延长连接的生命周期。如果消息要发送到某个类的特定实例,请在该类中存储一个connections 实例,实例销毁后您将不会收到消息。
基于@lpapp 发现的第二种方法是,如果您有一个只想调用一次以响应信号的 lambda,然后断开连接:
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 );
};
这里我们one_shot_connect( bob, &Bob::mySignal, [](QString str) { std::cout << "Hello\n" } );,下次信号触发时我们会收到消息,然后连接断开。
我在处理您的 lambda 之前断开连接,以防 lambda 导致信号触发或发生其他情况。