Boost logo

Boost :

From: Marcus Lindblom (macke_at_[hidden])
Date: 2007-05-15 11:47:36


Peter Dimov wrote:
> Marcus Lindblom wrote:
>> I can only add that I've found myself lacking this as well. (My
>> workaround is to pass a boost::function type as well, to get the
>> signature info. Not nice, but works.)
> Can you please show some use cases for this?
I have my own c++ <-> xml bind system that binds directly to member
functions, but also to generic function objects.

It allows syntax like:

ScriptClassImpl<Foo>.attr("my_attribute").bind(&Foo::bar);
ScriptClassImpl<Foo>.element("my_element").bind(&Foo::baz, "arg_1",
"arg_2");
ScriptClassImpl<Foo>.attr("my_attribute") = my_free_function; //
(my_free_function takes Foo* and xml-node)

In the bind()-cases, it uses mem_fn to call the actual function:

template<class C>
template<class T, typename A1, typename A2>
void ScriptClassImpl<C>::ElemBinder::bind(void (T::*f)(A1, A2),
                                          const char* n1, const char* n2)
{
    BOOST_STATIC_ASSERT((::boost::is_base_and_derived<T,
C>::value||::boost::is_same<T, C>::value));

    typedef boost::function<void (T&, A1, A2)> func_type;
    *m_f = xml::mkApplyElemFunctor<func_type>(boost::mem_fn(f),
*m_log).arg(n1).arg(n2);
}

I'd like to avoid the use of func_type here, it's just a type-info
carrier. (I could probably use a mpl::list or something with less baggage)

ApplyElemFunctor translates xml into an actual function call, in it's
operator():

template<class BF, typename F>
class ApplyElemFunctor :
    public ApplyElemFunctorStore
{
public:
    typedef typename boost::remove_reference<typename
BF::arg1_type>::type obj_type;

    ApplyElemFunctor(base::Logger& log, F& f);

    /// catches and reports any errors when invoking function
    bool operator () (obj_type& obj, const xmlNodePtr& in, xmlNodePtr& out);

private:
    // do-call is specialized for each arity (1 to 5 at the moment)

    template<>
    void doCall<3>(obj_type& obj, const xmlNodePtr& in, xmlNodePtr& out)
    ...
};

template<class BF, class F>
bool ApplyElemFunctor<BF, F>::operator () (obj_type& obj, const
xmlNodePtr& in, xmlNodePtr& out)
{
    try {
        doCall<BF::arity>(obj, in, out);
        return true;
    } catch(internal::XMLArgFailed &e) {
        e.report(in, out, m_log);
        return false;
    }
}

template<class BF, class F>
template<>
void ApplyElemFunctor<BF, F>::doCall<3>(obj_type& obj, const xmlNodePtr&
in, xmlNodePtr& out)
{
    typedef internal::arg_type<BF::arg2_type>::type a1;
    typedef internal::arg_type<BF::arg3_type>::type a2;

    m_f(obj, getAttr<a1>(in, 0), getAttr<a2>(in, 1));
}

So, doCall() is where I have to use BF (boost::function) rather than F
(boost::mem_fn) since mem_fn doesn't expose it's arg-types or arity.
(getAttr<> does argument name lookup & lexical_cast to type, or
object-lookup if it's a pointer type)

There might be a better way to do all this, as it is my first attempt at
c++ language binding after all. But it has worked remarkably well for
the last 1.5 years in service. :)

Cheers,
/Marcus


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