如何在不存储连接的情况下断开lambda函数

时间:2014-10-24 17:19:49

标签: c++ qt c++11 lambda

有没有办法在不存储连接对象的情况下断开对lambda函数的Qt连接?

我知道如果我存储从connect函数返回的QMetaObject::Connection可能会这样做,但我并不是真的想这样做,因为会有很多这样做。我主要连接到lambda函数,以避免创建一堆一次性方法和对象,似乎我需要做所有那些SLOTs更优选的簿记。

4 个答案:

答案 0 :(得分:15)

假设连接:

QObject::connect(senderInstance, &Sender::mySignal, this, []() {
    // implement slot as a lambda
});

然后您可以通过以下方式轻松断开连接:

QObject::disconnect(senderInstance, &Sender::mySignal, this, nullptr);

这会断开this's的所有Sender::mySignal个广告位;但是,只有一个这样的插槽是很常见的,因此最终的结果是断开连接简单且没有副作用。

答案 1 :(得分:7)

您可以使用虚拟对象:

QObject *obj = new QObject(this);
QObject::connect(m_sock, &QLocalSocket::readyRead, obj, [this](){
   obj->deleteLater();

当obj被销毁时,连接断开,因为你在连接上传递了obj。

答案 2 :(得分:4)

以下两种隐藏簿记问题的方法。

首先,我们维护一个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导致信号触发或者什么。

答案 3 :(得分:1)

这是写这篇文章的唯一方法:

QMetaObject::Connection connection =
    QObject::connect(psender, &MyClass::mySignal, [] () { /* Do the work */ });
QObject::disconnect(connection);

有关断开连接方法的参考,请参阅documentation

  

bool QObject :: disconnect(const QMetaObject :: Connection&amp; connection)[静态]

     

断开连接。

     

如果连接无效或已断开连接,请不执行任何操作并返回false。

在一天结束的时候,你仍然会用插槽来保存书籍,只有当你真的需要本地化时,lambda似乎更加本地化,​​所以这取决于你的个人喜好,我认为。 / p>

相关问题