Hier sind zwei Ansätze, um die Buchhaltungsprobleme zu verbergen.
Erstens halten wir eine std::vector
, die auf Zerstörung, uns von der Quelle trennt:
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;
Dann schließen wir wie folgt vor:
connections conns;
conns.emplace_back(QtConnect(bob, &Bob::mySignal, [](QString str){ std::cout << "Hello World!\n"; }));
, wenn der Vektor zerstört wird, die Verbindungsobjekte sind auch zerstört.
Dies ist vergleichbar mit anderen Signal/Slot-Systemen, bei denen der Listener ein Token verfolgt und dann zurückgibt. Aber hier halte ich das Trennungsobjekt in einem undurchsichtigen Typ, der die Verbindung bei der Zerstörung aufräumt.
Beachten Sie, dass das Kopieren dieses Vektors die Lebensdauer der Verbindung verlängert. Wenn die Nachricht an eine bestimmte Instanz einer Klasse weitergeleitet wird, speichern Sie eine connections
Instanz in der Klasse, und Sie erhalten keine Nachrichten, nachdem die Instanz zerstört wurde.
Ein zweiter Ansatz, der vor, was gefunden @lpapp, ist, wenn Sie einen Lambda haben, die Sie nur einmal in Reaktion auf ein Signal anrufen wollen, dann trennen:
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);
};
wir hier one_shot_connect(bob, Bob::mySignal, [](QString str) { std::cout << "Hello\n" });
und das nächste Mal, wenn das Signal ausgelöst wird, erhalten wir die Nachricht, und dann wird die Verbindung getrennt.
Ich trennen Sie vor der Verarbeitung Ihres Lambda, nur für den Fall, dass das Lambda das Signal zu feuern oder etwas verursacht.
Wie würden Sie sich vorstellen, dass Sie dies tun würden, ohne wieder einen Zustand zu speichern? – Yakk
Ich kann mir nicht vorstellen, wie, deshalb habe ich die Gemeinde gefragt. Es scheint nur so, als ob die Lambda-Syntax für Fälle, in denen eine Trennung erforderlich ist, nicht sehr nützlich ist. –