[signals] Replacing a connected slot

I have a class that needs to react to a particular signal. However, the manner in which it handles the signal is state dependent. I would, therefore, like to change the connected slot when necessary. In general, this is not a problem. However, changing the connection inside another slot is problematic. For example, assume that Foo::bar() is already connected to signal_, and signal_() is called... void Foo:: bar() { std::cout << "Foo::bar()\n"; current_connection_.disconnect(); current_connection_ = signal_.connect( boost::bind(&Foo::bar1, this)); } void Foo:: bar1() { std::cout << "Foo::bar1()\n"; } What I want to happen is that bar() will be called, then it will be disconnected, and bar1 will then be connected in its place. For example, given this calling sequence... signal_(); signal_(); I expect to see... Foo::bar() Foo::bar1() However, sometimes I may see... Foo::bar() Foo::bar1() Foo::bar1() because bar1() MAY get connected AFTER the place where bar() used to be connected, resulting in it also being called for the same signal invocation. What I think I want is a way to "replace" a connected slot, without disturbing anything else... void Foo:: bar() { std::cout << "Foo::bar()\n"; current_connection_.replace_slot(&Foo::bar1, this); } This is especially important if the slot is originally connected with... signal_.connect( invocation_level, boost::bind(&Foo::bar1, this)); because I see no way to retrieve the ordering information from the connection. In any event, how do you suggest I "replace" a conected slot, while still guaranteeing that the "connection" is invoked exactly once? Thanks!!!

On Nov 24, 2004, at 9:31 AM, Jody Hagins wrote:
In any event, how do you suggest I "replace" a conected slot, while still guaranteeing that the "connection" is invoked exactly once?
Oh, yuck. This is something the signals interface just can't handle... suggestions are welcome. Doug

On Wed, 24 Nov 2004 11:57:55 -0500 Doug Gregor <dgregor@cs.indiana.edu> wrote:
On Nov 24, 2004, at 9:31 AM, Jody Hagins wrote:
In any event, how do you suggest I "replace" a conected slot, while still guaranteeing that the "connection" is invoked exactly once?
Oh, yuck. This is something the signals interface just can't handle...
suggestions are welcome.
OK, I made a brief attempt. Diffs (diff -rc) are attached if you want to take a look... Basically... 1. added template typed_connection, which inherits from connection, so that a connection object can know the type of the signal (and ultimately the slot). This new class has a replace_slot() method that will replace the slot of the connection. 2. added a free function signals::detail::replace_slot() which mucks around with the internals and swaps out the slot in the connection with a new slot. 3. changed the return type of connect() to be the exact connection type. This should remain backward compatible since the return type used to be connection. Here is a simple example... #include "boost/signals.hpp" #include "boost/bind.hpp" #include <iostream> struct slot { slot( boost::signal<void (char const *)> & sig) : conn_(sig.connect(boost::bind(&slot::one, this, _1))) { } void one(char const * s) const { std::cout << "one()(" << s << ")\n"; conn_.replace_slot(boost::bind(&slot::two, this, _1)); } void two(char const * s) const { std::cout << "two()(" << s << ")\n"; conn_.disconnect(); } operator bool() const { return conn_.connected(); } boost::signal<void (char const *)>::connection_type conn_; }; int main( int argc, char * argv[]) { boost::signal<void (char const *)> sig; for (int i = 1; i < argc; ++i) { slot s(sig); while (s) { sig(argv[i]); } } }
participants (2)
-
Doug Gregor
-
Jody Hagins