Oooh, what's perfect forwarding?

Anyway, back to your previous question - no, I don't have 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 types
template<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 to
class 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 events
template<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 queue
void 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@lindenlab.com> 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@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users