[signals2] can a combiner return the slot iterator range?
I'd like a combiner to return the slot iterator as a range. 1. What is the type of the iterator? (any exposed meta function to get this? I couldn't see in the docs) 2. Are the itertors valid after the combiner returns? 3. Is this already possible without a custom combiner? E.g. template<class T> struct MyRangeCombiner { typedef boost::iterator_range< some_meta<T>::type > result_type; template<class It> result_type operator()(It begin, It end) const { return boost::make_iterator_range(begin,end); } }; class ComboSlot { public: void method1(int i) {..} void method2(double d) {..} }; boost::signals2::signal< ComboSlot&() , MyRangeCombiner<ComboSlot> > sig; // in use for( ComboSlot& cs : sig() ) { cs.method1(3); cs.method2(3.14); } A broader picture is the following: More often than not I have a family of events (signals). The slots are connected in groups, such as the the ComboSlot above. One straightforward implementation is to maintain different signals for every method: ComboSlot cs; boost::signals2::signal< void(int) > sigMethod1; boost::signals2::signal< void(double) > sigMethod2; sigMethod1.connect( &ComboSlot::method1, _1 ); sigMethod2.connect( &ComboSlot::method2, _1 ); ... There is quite a bit of waste associated with above. Not only it requires more code, but also we know for sure that if method1 is connected, so will method2, and they will be connected to slots who calls the corresponding method on the same ComboSlot. One other alternative is to write a combiner which loops and calls the method within operator(). Returning a range would be a better alternative. Thanks Nick
On Thu, Aug 6, 2015 at 4:01 PM, Nick Stokes
I'd like a combiner to return the slot iterator as a range.
1. What is the type of the iterator? (any exposed meta function to get this? I couldn't see in the docs) 2. Are the itertors valid after the combiner returns? 3. Is this already possible without a custom combiner?
I'm not sure what you're shooting for. When I'm approaching signals/slots or any sort of event driven system, I generally treat that as a single event, with 2+ connections, events being handled but each subscriber. i.e. your first connection handles the double value; the second connection would accept a double, and convert it to int to pass it along to another int-based method Along these lines.
E.g.
template<class T> struct MyRangeCombiner { typedef boost::iterator_range< some_meta<T>::type > result_type;
template<class It> result_type operator()(It begin, It end) const { return boost::make_iterator_range(begin,end); } };
class ComboSlot { public: void method1(int i) {..} void method2(double d) {..} };
boost::signals2::signal< ComboSlot&() , MyRangeCombiner<ComboSlot> > sig;
// in use for( ComboSlot& cs : sig() ) { cs.method1(3); cs.method2(3.14); }
A broader picture is the following: More often than not I have a family of events (signals). The slots are connected in groups, such as the the ComboSlot above. One straightforward implementation is to maintain different signals for every method:
ComboSlot cs; boost::signals2::signal< void(int) > sigMethod1; boost::signals2::signal< void(double) > sigMethod2; sigMethod1.connect( &ComboSlot::method1, _1 ); sigMethod2.connect( &ComboSlot::method2, _1 );
...
There is quite a bit of waste associated with above. Not only it requires more code, but also we know for sure that if method1 is connected, so will method2, and they will be connected to slots who calls the corresponding method on the same ComboSlot.
One other alternative is to write a combiner which loops and calls the method within operator(). Returning a range would be a better alternative.
Thanks Nick
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Thu, Aug 6, 2015 at 4:10 PM, Michael Powell
wrote: I'm not sure what you're shooting for.
Doesn't the last "broader picture" paragraph help explain?
When I'm approaching signals/slots or any sort of event driven system, I generally treat that
"that" == ?
as a single event, with 2+ connections, events being handled but each subscriber.
i.e. your first connection handles the double value; the second connection would accept a double, and convert it to int to pass it along to another int-based method
The 2+ methods (of ComboSlot) corresponds to entirely independent events. The event driven system fires them separately on separate code paths. The system fires as many of any of these in any order and count. The only invariant I want to impose is that they are always connected (or unconnected) in groups. I.e. there is no allowed scenario where a event1 is handled but event2 isn't, and both events are handled by the same underlying handler (ComboSlot). Again, is my "broader picture" example useful in anyway? Thanks Nick
On Thu, Aug 6, 2015 at 4:20 PM, Nick Stokes
On Thu, Aug 6, 2015 at 4:10 PM, Michael Powell
wrote: On Thu, Aug 6, 2015 at 4:01 PM, Nick Stokes
wrote: I'm not sure what you're shooting for.
Again, is my "broader picture" example useful in anyway?
perhaps, the short "use-case" example I provided was misleading:
// in use for( ComboSlot& cs : sig() ) { cs.method1(3); cs.method2(3.14); }
This gives the false impression that I am calling both methods in order. That is very misleading indeed, sorry. Here is perhaps a more clarifying use case: struct EventGenerator { void event1( int i ) { // want to launch all listeners of event1 } void event2( double d) { // want to launch all listeners of event2 } }; One implementation is to define two separate signals for each even and manage their slots independently: struct EventGenerator { typedef signal< void(int) > sig1_t; typedef signal< void(double) > sig2_t; void event1( int i ) { sig1(i); } void event2( double d) { sig2(d); } void connect( std::shared_ptr<ComboSlot>& e ) { sig1.connect( sig1_t::slot_type( &ComboSlot::method1, e.get(), _1 ).track(e) ); sig2.connect( sig2_t::slot_type( &ComboSlot::method2, e.get(), _1 ).track(e) ); } private: sig1_t sig1; sig2_t sig2; }; The invariant that signals must be connected together to a same underlying event handler is satisfied. But this implementation quickly gets out of hand as number of events increase. Another alternative would be: struct EventGenerator { typedef signal< ComboSlot&(), RangeCombiner > sig_t; void event1( int i ) { for( ComboSlot& cs : sig() ) { cs.method1(i); // also imagine, i can do arbitrary things there. e.g. break loop what not } } void event2( double d) { for( ComboSlot& cs : sig() ) { cs.method2(d); } } void connect( std::shared_ptr<ComboSlot>& e ) { ComboSlot* cs = e.get(); sig.connect( sig_t::slot_type( [cs](){ return cs;} ).track(e) ); // done - number of events don't matter } private: sig_t sig; }; hopefully this clarifies the use case. Thanks Nick
On Thu, Aug 6, 2015 at 4:37 PM, Nick Stokes
On Thu, Aug 6, 2015 at 4:20 PM, Nick Stokes
wrote: On Thu, Aug 6, 2015 at 4:10 PM, Michael Powell
wrote: On Thu, Aug 6, 2015 at 4:01 PM, Nick Stokes
wrote: I'm not sure what you're shooting for.
Again, is my "broader picture" example useful in anyway?
If it's my, I try to drive toward simplicity. I'm not sure what your real world requirements are, or how these many facets necessarily grew feet, per se, to answer beyond what I have. I do know that's one of the "features" of a pattern like event handling, signals/slots in particular, is to decouple the consumer from the producer, so that you don't need to know whether you are producing a 3.14 (PI) or a 3 (presumably, derived from the same PI value). Could say, 2.718 (e) or 2, for the same illustration, no? To me that's just another subscriber on the signaled method. HTH
perhaps, the short "use-case" example I provided was misleading:
// in use for( ComboSlot& cs : sig() ) { cs.method1(3); cs.method2(3.14); }
This gives the false impression that I am calling both methods in order. That is very misleading indeed, sorry. Here is perhaps a more clarifying use case:
struct EventGenerator {
void event1( int i ) { // want to launch all listeners of event1 }
void event2( double d) { // want to launch all listeners of event2 } };
One implementation is to define two separate signals for each even and manage their slots independently:
struct EventGenerator { typedef signal< void(int) > sig1_t; typedef signal< void(double) > sig2_t;
void event1( int i ) { sig1(i); }
void event2( double d) { sig2(d); }
void connect( std::shared_ptr<ComboSlot>& e ) { sig1.connect( sig1_t::slot_type( &ComboSlot::method1, e.get(), _1 ).track(e) ); sig2.connect( sig2_t::slot_type( &ComboSlot::method2, e.get(), _1 ).track(e) ); } private: sig1_t sig1; sig2_t sig2; };
The invariant that signals must be connected together to a same underlying event handler is satisfied. But this implementation quickly gets out of hand as number of events increase.
Another alternative would be:
struct EventGenerator { typedef signal< ComboSlot&(), RangeCombiner > sig_t;
void event1( int i ) { for( ComboSlot& cs : sig() ) { cs.method1(i); // also imagine, i can do arbitrary things there. e.g. break loop what not } }
void event2( double d) { for( ComboSlot& cs : sig() ) { cs.method2(d); } }
void connect( std::shared_ptr<ComboSlot>& e ) { ComboSlot* cs = e.get(); sig.connect( sig_t::slot_type( [cs](){ return cs;} ).track(e) ); // done - number of events don't matter } private: sig_t sig; };
hopefully this clarifies the use case.
Thanks Nick
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
On Thu, Aug 6, 2015 at 5:26 PM, Michael Powell
If it's my, I try to drive toward simplicity. I'm not sure what your real world requirements are, or how these many facets necessarily grew feet, per se, to answer beyond what I have.
I do know that's one of the "features" of a pattern like event handling, signals/slots in particular, is to decouple the consumer from the producer, so that you don't need to know whether you are producing a 3.14 (PI) or a 3 (presumably, derived from the same PI value). Could say, 2.718 (e) or 2, for the same illustration, no? To me that's just another subscriber on the signaled method.
HTH
Sorry, not really. I honestly appreciate your attempt to help, but so far you are providing non-answers. Can you please try to understand the requirement based on my latter example? I'd be happy to provide more clarification if the code isn't clear. Thanks Nick
participants (2)
-
Michael Powell
-
Nick Stokes