c++ - Elegant way to disconnect slot after first call -


inside constructor, there connection:

connect(&amskspace::on_board_computer_model::self(),       signal(camera_status_changed(const amskspace::camera_status_t&)),       this,       slot(set_camera_status(const amskspace::camera_status_t&))); 

and method:

void camera_model:: set_camera_status(const amskspace::camera_status_t& status) {   disconnect(&amskspace::on_board_computer_model::self(),              signal(camera_status_changed(const amskspace::camera_status_t&)),              this,              slot(set_camera_status(const amskspace::camera_status_t&)));    // job } 

and i'd disconnect slot after first call.

the question is: there way call slot once? without explicit disconnection? single shot method? possible?

the core idea create wrapper, special "connect" automatically disconnect signal. usefull if use lot of "call me once" connections; otherwise i'd advice qobject::disconnect @ beginning of slot.

this implementation works creating 2 connections: "normal" one, , 1 disconnect & cleanup after.

an implementation (using c++11/qt 5, ):

template <typename func1, typename func2> static inline qmetaobject::connection weakconnect(         typename qtprivate::functionpointer<func1>::object *sender, func1 signal,         typename qtprivate::functionpointer<func2>::object *receiver, func2 slot) {      qmetaobject::connection conn_normal = qobject::connect(sender, signal, receiver, slot);      qmetaobject::connection* conn_delete = new qmetaobject::connection();      *conn_delete = qobject::connect(sender, signal, [conn_normal, conn_delete](){         qobject::disconnect(conn_normal);         qobject::disconnect(*conn_delete);         delete conn_delete;     });     return conn_normal; } 

caveats/things improve:

  • the cleanup occurs after calling regular slot. if regular slot causes signal emitted again, regular slot executed again (potentially causing infinite recursion).
  • no proper way disconnect, except emitting signal. (you can use qobject::disconnect, cause small memory leak)
  • relies on order of execution of slots. seems fine now.
  • the naming

tested using:

class : public qobject {     q_object signals:     void sig(int a); };   class b : public qobject {     q_object public:     b(int b) : qobject(), b_(b) {}     int b() const { return b_; } public slots:     void slo(int a) { qdebug() << "\tb :" << b_ << "a:" << a;  } private:     int b_; }; 

and

a a1; a2;  b b10(10); b b20(20);  weakconnect(&a1, &a::sig, &b10, &b::slo); weakconnect(&a1, &a::sig, &b20, &b::slo); weakconnect(&a2, &a::sig, &b20, &b::slo);  qdebug() << "a1 :"; emit a1.sig(1);// should trigger b10 , b20 slo qdebug() << "a2 :"; emit a2.sig(2);// should trigger b20 slo qdebug() << "a1 :"; emit a1.sig(3);// should nothing qdebug() << "a2 :"; emit a2.sig(4);// should nothing 

test code output:

a1 :     b : 10 a: 1     b : 20 a: 1 a2 :     b : 20 a: 2 a1 : a2 : 

getting rid of c++11/qt5 (i don't have qt 4.8/gcc4.4.7, not tested those) according doc, qt 4.8 doesn't have connect function, i'm using wrapper:

class connectjanitor : public qobject {     q_object public slots:     void cleanup()     {         qobject::disconnect(conn_normal_);         qobject::disconnect(*conn_delete_);         delete conn_delete_;         delete this;     } public:     static connectjanitor* make(qmetaobject::connection conn_normal,                                 qmetaobject::connection* conn_delete)     {         return new connectjanitor(conn_normal, conn_delete);     } private:     connectjanitor(qmetaobject::connection conn_normal,                    qmetaobject::connection* conn_delete) :         qobject(0) , conn_normal_(conn_normal), conn_delete_(conn_delete) {}      connectjanitor(const connectjanitor&); // not implemented     connectjanitor& operator=(connectjanitor const&);       qmetaobject::connection conn_normal_;     qmetaobject::connection* conn_delete_; }; 

(i'm making connectjanitor's constructor private because instance self-destructs (delete this))

and weakconnect:

static inline qmetaobject::connection weakconnect(const qobject * sender, const char * signal, const qobject * receiver, const char * slot) {     qmetaobject::connection conn_normal = qobject::connect(sender, signal, receiver, slot);     qmetaobject::connection* conn_delete = new qmetaobject::connection();     *conn_delete = qobject::connect(sender, signal, connectjanitor::make(conn_normal, conn_delete), slot(cleanup()));     return conn_normal; } 

if need manually break connections, suggest have weakconnect() returning connectjanitor's pointer.


Comments

Popular posts from this blog

java - Oracle EBS .ClassNotFoundException: oracle.apps.fnd.formsClient.FormsLauncher.class ERROR -

c# - how to use buttonedit in devexpress gridcontrol -

nvd3.js - angularjs-nvd3-directives setting color in legend as well as in chart elements -