|
Boost Users : |
Subject: Re: [Boost-users] [RFC] Signals bound to phoenix functions
From: Stephan Menzel (stephan.menzel_at_[hidden])
Date: 2010-06-23 11:42:49
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_at_[hidden]> 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
>
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net