C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)
引言
在之前的Qt項目中,我發(fā)現(xiàn)經(jīng)常會用到槽函數(shù)只需要執(zhí)行一次的情況。也就是說,槽函數(shù)執(zhí)行一次后,就需要disconnect對應(yīng)的連接。然而,真正操作起來實際上挺麻煩的,或者說不優(yōu)雅。
因為你需要把之前connect時產(chǎn)生的QMetaObject::Connection
對象保存起來,而保存它不能用局部變量,通常需要保存到類的成員變量中,或者其他生命周期足夠長的地方,以防止在disconnect它的時候,它已經(jīng)失效了。
總之,需要使用者自己維護(hù),因而增加了使用者的負(fù)擔(dān)。
如果有一個方法能夠在槽函數(shù)執(zhí)行完成后自動disconnect掉連接就好了。我在網(wǎng)上找了一段時間,卻沒有找到合適的解決方案,相關(guān)討論也比較少,可能這不是一個很常見的需求吧。不過還是在GitHub上找到了一個相關(guān)的庫:https://github.com/misje/once,但是看它的源碼,感覺比較復(fù)雜。
它針對QObject::connect
函數(shù)的每種情況,寫了對應(yīng)的實現(xiàn),總感覺太復(fù)雜了,應(yīng)該存在一種更通用的方法。
最近在閱讀了《C++ Primer》模板相關(guān)的章節(jié)后,我突然想到也許用完美轉(zhuǎn)發(fā)相關(guān)的東西可以簡化實現(xiàn)。于是試著寫了一下,貌似真得可以,代碼如下:
ConnectionUtil.h:
#pragma once #include <QObject> #include <QMap> namespace ConnectionUtil { typedef QMetaObject::Connection Conn; struct ConnKey {}; extern QMap<ConnKey*, QPair<Conn, Conn>> connMap; class ReceiverObj : public QObject { Q_OBJECT public: explicit ReceiverObj(ConnKey *connKey) : key(connKey) {} public slots: void slot(); private: ConnKey *key; }; // 處理信號為SIGNAL(...)的情況 template <typename Sender, typename ...Args> void connect(Sender &&sender, const char *signal, Args &&...args) { ConnKey *connKey = new ConnKey; Conn conn1 = QObject::connect(std::forward<Sender>(sender), signal, std::forward<Args>(args)...); Conn conn2 = QObject::connect(std::forward<Sender>(sender), signal, new ReceiverObj(connKey), SLOT(slot())); connMap.insert(connKey, qMakePair(std::move(conn1), std::move(conn2))); } // 處理其他情況 template <typename Sender, typename Signal, typename ...Args> void connect(Sender &&sender, Signal &&signal, Args &&...args) { ConnKey *connKey = new ConnKey; Conn conn1 = QObject::connect(std::forward<Sender>(sender), std::forward<Signal>(signal), std::forward<Args>(args)...); Conn conn2 = QObject::connect(std::forward<Sender>(sender), std::forward<Signal>(signal), [connKey] { ReceiverObj(connKey).slot(); }); connMap.insert(connKey, qMakePair(std::move(conn1), std::move(conn2))); } }
ConnectionUtil.cpp:
#include "ConnectionUtil.h" using namespace ConnectionUtil; QMap<ConnKey *, QPair<Conn, Conn>> ConnectionUtil::connMap; void ReceiverObj::slot() { const QPair<Conn, Conn> &connections = connMap.value(key); QObject::disconnect(connections.first); QObject::disconnect(connections.second); connMap.remove(key); delete key; deleteLater(); }
這個實現(xiàn)假定QObject::connect
的所有重載函數(shù)前兩個參數(shù)分別是Sender和Signal,事實上確實是這樣。關(guān)鍵點就是,額外建立一個連接,在收到信號后,disconnect用戶的連接。不過,我總感覺這個實現(xiàn)在多線程的情況下可能有bug,但在經(jīng)過簡單的測試后,暫時沒有發(fā)現(xiàn)。
使用示例如下:
ConnectionUtil::connect(this, SIGNAL(bong(int)), obj, SLOT(slotBong(int)), Qt::QueuedConnection); ConnectionUtil::connect(this, &MainWindow::bong, obj, &SomeObject::slotBong, Qt::QueuedConnection); ConnectionUtil::connect(this, &MainWindow::bong, this, []() { qDebug() << "bingo"; });
以上就是C++11 寫一個只觸發(fā)一次槽函數(shù)的Qt connect函數(shù)的詳細(xì)內(nèi)容,更多關(guān)于C++11 Qt connect函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++的STL中accumulate函數(shù)的使用方法
這篇文章主要介紹了C++的STL中accumulate的使用方法,accumulate作用是累加求和即自定義類型數(shù)據(jù)處理,下文具體的操作方法需要的小伙伴可以參考一下2022-03-03排列和組合算法的實現(xiàn)方法_C語言經(jīng)典案例
下面小編就為大家?guī)硪黄帕泻徒M合算法的實現(xiàn)方法_C語言經(jīng)典案例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法
這篇文章主要介紹了淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法,注意其將字符串轉(zhuǎn)換成long型的區(qū)別,需要的朋友可以參考下2015-08-08C++用兩個棧實現(xiàn)一個隊列(面試官的小結(jié))
這篇文章主要給大家介紹了關(guān)于C++用兩個棧實現(xiàn)一個隊列的相關(guān)資料,這是來自一名面試官的小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05C++ 數(shù)據(jù)結(jié)構(gòu)完全二叉樹的判斷
這篇文章主要介紹了C++ 數(shù)據(jù)結(jié)構(gòu)完全二叉樹的判斷的相關(guān)資料,需要的朋友可以參考下2017-06-06