|
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