Boost logo

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