Boost logo

Boost :

From: Christian Holmquist (c.holmquist_at_[hidden])
Date: 2006-12-19 08:52:20


First of all a great thank-you (!!!) to Joel and the rest behind the
development of fusion.
It's solved so many tasks for me and made me write so little code the past
months I probably shouldn't even get paid.
database-abstraction, remote function invocation with async handlers,
console/web interface invocation, etc.. It's changed my perception of
effective programming to a complete new level.
What before was a struggle with mpl, is now clean and easy.

Ok, so to my humble problem. I'm constantly finding myself writing those
overloaded functions like:

------------------
template<class A0, class A1, ....>
void operator()(const A0& a0, const A1& a1, ...) const
{
 do_something_very_clever(fusion_sequence_type(a0, a1, ...));
}
------------------

This is cumbersome and boring, and usually I just add the overloads when
someone else needs it.. It's not always the case I can know beforehand to
overload const T& or just T& also, but it depends on the use case.

Anyways, my idea is to generate the correct overloaded operator()(...) by
specializing on the size of the fusion sequence, instantiate the sequence
with the parameters when invoked by client code, and then use CRTP downcast
to invoke a function with the fusion sequence. This way I can do the job
with my neat fusion sequence without client-code needing to mess with
boost::fusion::tie and boost::ref etc, and I don't have to bother with the
overloads.
I guess an example would explain better than the above noise.
Here's what a trivial multi-dispatch function would look like. I use
function_types here to build my fusion sequence, but it could just as well
have been some preprocessor enumeration dito instead.
The overloading class selecting the overload is named to pack_args
(attached).

template<class Func>
struct simple_signal : public pack_args
<
simple_signal const,
typename
boost::fusion::result_of::as_vector<boost::function_types::parameter_types<Func>
>::type,
void
>
{
    typedef boost::function1<void, const sequence_type> function;

    template<class F>
    struct invoke
    {
        invoke(const F& f) : f_(f) {}
        void operator()(const sequence_type& seq) const
        {
            boost::fusion::unpack_args(f_, seq);
        }
        F f_;
    };

    template<class F>
    void connect(const F& f)
    {
        m_functions.push_back(invoke<F>(f));
    }

    // callback from pack_args. I agree this convention looks ugly, but
it'll do for now..
    void on_packed_args(const sequence_type& seq) const
    {
        for(std::list<function>::const_iterator i = m_functions.begin(); i
!= m_functions.end(); ++i)
        {
            (*i)(seq);
        }
    }
private:
    std::list<function> m_functions;
};

I can now use the above with
simple_signal<void(int const, int const) > sig;
sig(24, 54); // call all connected functions here..

If I have overlooked anything in fusion that would give me this
functionality, please point me in the right direction and I'll be forever
grateful :)

Regards,
Christian






Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk