2015-08-17 2 views
1

J'utilise un modèle comme celui-ci, 11 C++:Utiliser boost :: signals2 :: traçable avec lambdas

class FooViewController { 
    void build() { 
     auto label = ... 

     network->doWork([] (const Result& r) { 
      label->setText(r.text); 
     }); 
    } 
} 

FooViewController peut déconstruire avant doWork finalise, ce qui provoque des accidents. En regardant boost :: signals2, je pense à utiliser boost::signals2::trackable, ce qui fonctionne très bien pour mes objectifs à un seul thread, avec l'avantage que je ne dois pas gérer et gérer mes connexions directement, mais je ne suis pas sûr de savoir comment obtenir un tel une solution de travail avec lambdas.

est ici une version gratuite lambda de travail:

class Foo : public boost::signals2::trackable { 
public: 
    void bar() { 
     printf("Fire!"); 
    } 
}; 


Usage: 

    boost::signals2::signal<void()> signal; 
    { 
     Foo test; 
     signal.connect(boost::bind(&Foo::bar, &test)); 
     signal(); 
    } 
    signal(); 

Output: 

    Fired! 
    // Note a second 'Fired!' did not occur, which is correct behavior 

Deux objectifs:

1-- Je voudrais faire quelque chose comme:

signal.connect(boost::bind([] { 
    printf("Fired!"); 
}, &test)); 

qui ne serait pas appeler le lambda après test est démoli.

2-- Je ne souhaite pas gérer directement les objets de connexion renvoyés par .connect.

+0

Honnêtement, je ne sais pas ce que le lambda-vous d'acheter quand vous avez la 'bind()' autour de toute façon. Ne pouvez-vous pas simplement utiliser le 'trackable', puisque c'est toujours le premier paramètre lié? – sehe

+0

Je creuse les lambdas pour les captures. La liaison est apparue comme nécessaire lors de l'utilisation de traçabilité. Idéalement, smart_ptrs et track seraient naturels à signals2 (trackable est obsolète), mais il existe un mécanisme de compte de ref/autorelease pool existant dans l'application. Enquêter sur les prochaines étapes. – fionbio

Répondre

0

trouvé la réponse référencement trackable_test.cpp:

struct short_lived : public boost::signals2::trackable { 
    ~short_lived() { 
     cout << "I'm dying...!" << std::endl; 
    } 
}; 

void main() { 
    typedef boost::signals2::signal<void()> sig_type; 
    sig_type s1; 

    short_lived* shorty = new short_lived(); 
    s1.connect(boost::bind<void>([](const short_lived*) { 
     cout << "Fire!" << std::endl; 
    }, shorty)); 
    s1(); 
    delete shorty; 

    s1(); 
} 

Sortie

Fire! 
I'm dying...! 

... et un exemple multiple params (boost :: recyclage bind):

typedef boost::signals2::signal<void(int)> sig_type; 

// ...same... 

s1.connect(boost::bind<void>([](const short_lived*, int cannon) { 
    cout << "Fire " << cannon << "!" << std::endl; 
}, shorty, _1)); 
s(1); 
delete shorty; 
s(2); 

sortie

Fire 1! 
I'm dying...! 
0

Vous pouvez coder quelque chose de similaire en utilisant des pointeurs partagés/faibles:

Live On Coliru

#include <boost/signals2.hpp> 
#include <boost/make_shared.hpp> 
#include <boost/weak_ptr.hpp> 
#include <iostream> 

class Foo : public boost::signals2::trackable { 
public: 
    void bar() { 
     printf("Fire!\n"); 
    } 
}; 

int main() { 
    boost::signals2::signal<void()> signal; 
    { 
     auto test = boost::make_shared<Foo>(); 

     signal.connect([wp = boost::weak_ptr<Foo>(test)] 
       { 
        if (auto sp = wp.lock()) 
         sp->bar(); 
        else 
         std::cout << "expired\n"; 
       } 
      ); 

     signal(); 
    } 
    signal(); 
} 

Imprime

Fire! 
expired 

strictement C++ version 11: Live On Coliru

+0

Merci pour ce @sehe. Pour les pointeurs intelligents, j'utiliserais certainement ceci ou [track] (http://www.boost.org/doc/libs/1_39_0/doc/html/signals2/tutorial.html#signals2.tutorial.connection-management), mais le les objets de cette application sont actuellement gérés via un objet personnalisé compté ref pour une utilisation dans un pool autorelease. Je pense que je suis à la recherche d'une solution pour simuler mon propre smart_ptr à utiliser dans la piste, où les tripes interagiraient correctement avec le ref tracker/pool existant. Pas encore totalement clair. Toujours à la recherche ... – fionbio

1

Comme on peut le voir here: « L'utilisation de la classe traçable n'est pas recommandé pour le nouveau code »

Peut-être choisir d'aller avec scoped_connection ou track à la place.

Exemple:

#include <iostream> 
#include <memory> 

#include <boost/signals2.hpp> 


struct short_lived : public boost::signals2::scoped_connection { 
public: 
    short_lived(const boost::signals2::connection &conn) : boost::signals2::scoped_connection{conn} 
    { } 
    ~short_lived() { 
     std::cout << "I'm dying...1!" << std::endl; 
    } 

}; 

int main() { 
    typedef boost::signals2::signal<void()> sig_type; 
    sig_type s1; 

    { 
     /* boost::signals2::scoped_connection */ short_lived conn{s1.connect([]() { 
        std::cout << "Fire1!" << std::endl; 
       })}; 
     s1(); 
    } 
    s1(); 
    std::cout << std::endl; 

    { 
     auto lam = []() { 
     std::cout << "Fire2!" << std::endl; 
     }; 

     /* shared_ptr with custom deleter that does not delete (since we didn't use new), 
     but prints a message */ 
     std::shared_ptr<decltype(lam)> sptr{&lam, [](decltype(lam) *) { std::cout << "I'm dying...2!" << std::endl; }}; 
     s1.connect(sig_type::slot_type(lam).track_foreign(sptr)); 
     s1(); 
    } 
    s1(); 

    return 0; 
} 

http://melpon.org/wandbox/permlink/c8LHGIp8ArkKsnWA

+0

Nice - vous devez garder sur shared_ptrs pour les fonctions à vivre cependant. – fionbio