|
Boost Users : |
Subject: Re: [Boost-users] [bind] & [function] How do I store member functions with generalised arguments for later invocation?
From: Steve Lorimer (steve.lorimer_at_[hidden])
Date: 2010-06-04 10:18:38
Oooh, what's perfect forwarding?
Anyway, back to your previous question - no, I don't *hav*e to hide the
boost::bind etc, but I think my concept will wrap up a lot of functionality
rather nicely, and I don't think the calling point will look too ugly.
This is what I expect the creation of an event object to look like (using
the code detailed below)
shared_ptr<event> ev = create_event<foo, bar>(obj, &foo::func, queue); //
this for class *foo*, which has member *void foo::func(bar)* which we want
to callback to
To post an event to be processed by another queue will look like this
post_to_event<bar>(ev, data); // posts an object *data* of type *foo* to
event *ev*
So here's the code that I have come up with - doesn't compile though (of
course!) - what do you think?
// cross-thread event queue. multiple threads can post jobs, one or
many threads can execute// jobs.class EventQueue
{public:
typedef boost::function<void()> Job;
private:
boost::mutex mtx_;
boost::condition cnd_;
typedef std::list<Job> Jobs;
Jobs jobs_;
int stop_;
// puts a job into the queue
void post(Job job)
{
boost::mutex::scoped_lock lock(mtx_);
jobs_.push_back(job);
cnd_.notify_one();
}
public:
// pulls one job from the queue, returns false when stopped
bool pull(Job* job)
{
boost::mutex::scoped_lock lock(mtx_);
for(;;)
{ // handle spurious wake-ups
while(!stop_ && jobs_.empty())
cnd_.wait(lock);
if(!jobs_.empty() && 2 != stop_)
{
job->swap(jobs_.front()); // move efficiently,
avoiding *job = jobs.front()
jobs_.pop_front();
return true;
}
else if(stop_)
{
return false;
}
}
}
// make pull() return false
void stop(bool cancel_jobs)
{
boost::mutex::scoped_lock lock(mtx_);
stop_ = 1 + cancel_jobs; // 1 - complete jobs, 2 - cancel jobs
cnd_.notify_all();
}
EventQueue() : stop_() {}
~EventQueue() { this->stop(true); }
// event post friends
friend void post_to_event(boost::shared_ptr<event> &ev);
template<typename A0>
friend void post_to_event(boost::shared_ptr<event> &ev,
boost::shared_ptr<A0> &data);
};//-----------------------------------------------------------------------
// typedef generalised callback typestemplate<class T>struct cb0
{
typedef void (T::*type)(); // member function of the form 'T::fn()'
};
template<class T, typename A0>struct cb1
{
typedef void (T::*type)(boost::shared_ptr<A0>); // member function
of the form 'T::fn(shared_ptr<A0>)'
};//-----------------------------------------------------------------------
// the event class which keeps track of our job and the queue we want
to post the job toclass event
{
EventQueue &queue_; // the event queue which
will process the job
EventQueue::Job job_;
event(EventQueue &queue, EventQueue::Job &job) : queue_(queue),
job_(job) { }
// event creation friends
template<typename T>
friend boost::shared_ptr<event> create_event(boost::shared_ptr<T>
that, typename cb0<T>::type cb, EventQueue &queue);
template<typename T, typename A0>
friend boost::shared_ptr<event> create_event(boost::shared_ptr<T>
that, typename cb1<T, A0>::type cb, EventQueue &queue);
// event post friends
friend void post_to_event(boost::shared_ptr<event> &ev);
template<typename A0>
friend void post_to_event(boost::shared_ptr<event> &ev,
boost::shared_ptr<A0> &data);
};
// helper functions which create new eventstemplate<typename T>
boost::shared_ptr<event> create_event(boost::shared_ptr<T> that,
typename cb0<T>::type cb, EventQueue &queue)
{
// encapsulate an object and it's member function using bind
return boost::shared_ptr<event>(new event(queue, boost::bind(cb, that)));
}
template<typename T, typename A0>
boost::shared_ptr<event> create_event(boost::shared_ptr<T> that,
typename cb1<T, A0>::type cb, EventQueue &queue)
{
// encapsulate an object and it's member function using bind,
placeholder for argument to come
return boost::shared_ptr<event>(new event(queue, boost::bind(cb,
that, _1)));
}//-----------------------------------------------------------------------
// helper functions which post events onto the event's queuevoid
post_to_event(boost::shared_ptr<event> &ev)
{
ev->queue_.post(ev->job_);
}
template<typename A0>void post_to_event(boost::shared_ptr<event> &ev,
boost::shared_ptr<A0> &data)
{
// bind the data to the job
ev->queue_.post(boost::bind(ev->job_, data));
}//-----------------------------------------------------------------------
On 4 June 2010 15:05, Nat Goodspeed <nat_at_[hidden]> wrote:
> Nat Goodspeed wrote:
>
> boost::signals2::slot (in boost/signals2/slot.hpp) does wrap a bind() call
>> in a way that you might adapt if this is what you want.
>>
>
> I intended to add: if you don't mind requiring a C++1x-compliant compiler,
> you could use perfect forwarding instead.
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
>
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