如何在不存储连接的情况下断开Lambda函数 [英] How to disconnect a lambda function without storing connection

查看:101
本文介绍了如何在不存储连接的情况下断开Lambda函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在不存储连接对象的情况下断开与lambda函数建立的 Qt 连接?



我知道如果我存储从connect函数返回的 QMetaObject :: Connection 是有可能的,但是我并不是很想这样做,因为会有很多他们。我主要连接到lambda函数,以避免创建一堆的一次性方法和对象,并且如果我需要做所有记账工作,则 SLOTs 会更可取。

解决方案

这里有两种隐藏簿记问题的方法。



首先,我们维护一个 std :: vector ,该销毁后会使我们与源断开连接。

  typedef std :: shared_ptr< void> listen_token; 

结构隔离器{
QMetaObject :: Connection conn;
断开器(QMetaObject :: Connection&& c):conn(std :: move(c)){}
〜disconnecter(){QObject :: disconnect(conn); }
};

template< F类,T类,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 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<类别T,类别M,类别F>
void one_shot_connect(T * t,M * m,F& f){
typedef typename std :: decay< F> :: type X;
auto_disconnect_t< X>助手(std :: forward< F>(f));
* helper.conn = QObject :: connect(t,m,helper);
};

在这里,我们 one_shot_connect(bob,& Bob :: mySignal,[] (QString str){std :: cout<< Hello\n}); ,下一次触发信号时,我们会收到消息,然后断开连接。 / p>

在处理您的lambda之前,我会断开连接,以防lambda导致信号触发或发生某些事情。


Is there a way to disconnect Qt connections that are made to lambda functions without storing connection objects?

I know it's possible to do if I store the QMetaObject::Connection returned from the connect function, but I don't really want to do that because there would be a ton of them. I mainly connect to lambda functions to avoid creating a bunch of one-off methods and objects, and it seems like if I need to do all that bookkeeping that SLOTs would be more preferable.

解决方案

Here are two approaches to hide the bookkeeping issues.

First, we maintain a std::vector which, on destruction, 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 the vector is destroyed, the connection objects are also destroyed.

This is similar to how other signal/slot systems are handled, where the listener keeps track of a token, then returns it. But here, I keep the disconnection object in an opaque type that cleans up the connection on destruction.

Note that copying that vector will extend the lifetime of the connection. If the message is going to a particular instance of a class, store a connections instance in the class, and you won't get messages after the instance is destroyed.


A second approach, based off what @lpapp found, is if you have a lambda that you want to call only once in response to a signal, then disconnect:

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 one_shot_connect( bob, &Bob::mySignal, [](QString str) { std::cout << "Hello\n" } );, and the next time the signal fires we get the message, and then the connection is disconnected.

I disconnect before processing your lambda, just in case the lambda causes the signal to fire or something.

这篇关于如何在不存储连接的情况下断开Lambda函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆