
Hi, maybe I managed to narrow it down a little. This works for both functors and member functions: class Queue { ... template<typename SlotSignature, typename SlotFunction> boost::signals2::connection connect(boost::signals2::signal<SlotSignature> &n_signal, SlotFunction n_method) { return n_signal.connect(m_iosrv.wrap( n_method)); }; ... } io_service::wrap basically does what I needed all the time. No more wrapper. Unless I want to add something. Unfortunately I can't always take wrap()s output but have to modify a little. In fact, my Queue needs to be templatized as well, modifying the behaviour of the functor. I have a template parameter "Calling". When it is true, another function shall be called by the functor after the method was posted. Now I wanted to do this by phoenix: template <bool Calling> class Queue { template<typename Handler> void post(Handler n_handler) { m_iosrv.post(n_handler); }; ... template<typename SlotSignature, typename SlotFunction> boost::signals2::connection connect(boost::signals2::signal<SlotSignature> &n_signal, SlotFunction n_method) { return n_signal.connect( if_( CallingBack ) [ post(n_method) , m_signal_callback() ] .else_ [ m_iosrv.wrap( n_method ) ] ); }; ... private: boost::function<void ()> m_callback; boost::asio::io_service m_iosrv; } Now as I understand phoenix the if_ statement is supposed to give me a functor that is composed of either what is in the true section or the false section, depending on the expression at compile time. Which I guess is what I want. Alas, even after some days of trial and error I can't get it to compile. It seems like the if_ operator is not accepted properly. Or I am completely misunderstanding phoenix. ... no match for »operator[]« in »boost::phoenix::if_ [with Cond = bool](((const bool&)((const bool*)(& false))))[(Queue<Calling>::post [with Handler = queue_testsuite::testslot, bool Calling = false]((n_method, queue_testsuite::testslot())), ((Queue<false>*)this)->Queue<false>::m_signal_callback.boost::function<void()>::<anonymous>.boost::function0<R>::operator() [with R = void]())]« ... Any ideas anyone?? Cheers, Stephan On Mon, Jun 21, 2010 at 11:14 AM, Stephan Menzel <stephan.menzel@gmail.com> wrote:
G'day,
I'd like to get your opinion on a problem that puzzles me for a while. Basically, I'm trying to do sort of a delayed signals2 notification mechanism. I have a class wrapped around ASIOs io_service object that I normally use as a thread multiplexer and function storage. Now in this case I want to use it without working threads so a current thread can process whatever handlers are in it. Which works fine but now I want to connect signals to it. I have several data classes that contain signals. These are to be connected to slots, but not directly. Instead, these slots are to be wrapped in little handlers and these handlers shall be put in the io_service object. So the signal's slot should not be executed straight away but by another thread that executes everything in the io_service.
Now this strikes me as something that could be done nicely with phoenix. I want to use phoenix to create a little function that I can connect to the signal and that will do nothing more but post the handler into the io_service when the signal is triggered. I just can't figure out if that can actually work. Here's what I have so far (simplyfied). I try to illustrate on an example with a one-parameter slot.
class Queue : public boost::noncopyable {
public: template<typename Handler> void post(Handler n_handler) { m_iosrv.post(n_handler); }
std::size_t process(boost::system::error_code & n_errcode) { return m_iosrv.poll(n_errcode); };
template<typename Slot> boost::signals2::connection connect(boost::signals2::signal<void()> &n_signal, Slot n_method) { return n_signal.connect(boost::bind(&CommandQueue::slotWrapper<Slot>, this, n_method)); }; template<typename Slot, typename T1> boost::signals2::connection connect(boost::signals2::signal<void(T1)>& n_signal, Slot n_method) { return n_signal.connect(boost::bind(&CommandQueue::slotWrapper<Slot, T1>, this, n_method, _1)); } // ... more to come with more parameters T2, T3.....
private: template<typename Slot> void slotWrapper(Slot n_method) { post(n_method); }
template<typename Slot, typename T1> void slotWrapper(Slot n_method, T1 t1) { boost::function<void(T1)> f(n_method); post(boost::bind(f, t1)); } // ... more to come with more parameters ...
boost::asio::io_service m_iosrv; };
Now I can use this like this:
struct testslot_one { void operator()(int n_arg) const { std::cout << "testslot 1: " << n_arg << std::endl; } };
main { Queue q; boost::signals2::signal<void (int)> sig1;
struct testslot_one t1; q.connect(sig1, t1);
// signal not yet executed but only the handler posted sig1(42);
boost::system::error_code errc; // here we execute the accumulated signals q.process(errc); }
Now this works OK so far but I have two problems:
First of all, the standard use case will be to bind member functions and not seperate functors such as "testslot_one" in this example. Which is when the connect fails. For reasons unknown to me. But that must work. Second, I want to get rid of the "slotWrapper" functions and replace them by a phoenix expression. If that makes sense, which I'm not sure of.
Also, I am not certain about the whole thing. Can a phoenix generated function actually serve this way? Just post the handler when the signal is triggered?
Any opinions are appreciated!
Cheers, Stephan