boost::mem_fn suggestion/question

Hello, I was using boost::mem_fun and noticed that only with the 1 or 2 argument form of boost::mem_fun exposes the arguments types (first_argument_type and second_argument_type) for "compatibility" purposes. I was wondering if it were possible to expose in general all argument types just like boost::function does ( arg1_type, arg2_type, etc..). Any ideas/comments about this? Thanks!

Piyo wrote:
Hello,
I was using boost::mem_fun and noticed that only with the 1 or 2 argument form of boost::mem_fun exposes the arguments types (first_argument_type and second_argument_type) for "compatibility" purposes. I was wondering if it were possible to expose in general all argument types just like boost::function does ( arg1_type, arg2_type, etc..).
Any ideas/comments about this? 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.)
Cheers, /Marcus

Marcus Lindblom wrote:
Piyo wrote:
Hello,
I was using boost::mem_fun and noticed that only with the 1 or 2 argument form of boost::mem_fun exposes the arguments types (first_argument_type and second_argument_type) for "compatibility" purposes. I was wondering if it were possible to expose in general all argument types just like boost::function does ( arg1_type, arg2_type, etc..).
Any ideas/comments about this?
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?

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

Marcus Lindblom wrote:
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); }
Sounds sensible, although you can use something like *m_f = boost::bind( f, _1, boost::bind( getArg<A1>, _2, n1 ), boost::bind( getArg<A2>, _2, n2 ) ); here. I'm somewhat reluctant to introduce features into boost::mem_fn since std::tr1::mem_fn and the upcoming std::mem_fn don't/won't have them. If you start using ::argN_type, you won't be able to switch to std::mem_fn once it becomes available. Of course if this is not a concern for the Boost community we can easily add the typedefs and the arity.

Peter Dimov wrote:
Marcus Lindblom wrote:
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); }
Sounds sensible, although you can use something like
*m_f = boost::bind( f, _1,
boost::bind( getArg<A1>, _2, n1 ), boost::bind( getArg<A2>, _2, n2 ) );
here.
Hmm. Yup, that might be possible. I'll have to think about it. :)
I'm somewhat reluctant to introduce features into boost::mem_fn since std::tr1::mem_fn and the upcoming std::mem_fn don't/won't have them. If you start using ::argN_type, you won't be able to switch to std::mem_fn once it becomes available. Of course if this is not a concern for the Boost community we can easily add the typedefs and the arity.
Valid point. Perhaps function_traits could be extended to handle all type of function objects as well as regular functions, somehow? Cheers, /Marcus

Peter Dimov wrote:
I'm somewhat reluctant to introduce features into boost::mem_fn since std::tr1::mem_fn and the upcoming std::mem_fn don't/won't have them. If you start using ::argN_type, you won't be able to switch to std::mem_fn once it becomes available. Of course if this is not a concern for the Boost community we can easily add the typedefs and the arity.
Hi Peter, Several questions: - when C++0x gets published and when compilers are fully tr1 compliant, do you see boost::mem_fn (and the rest of the tr1 overlap) go away from boost? - I was also interested into the rationale why it was omitted also. I was looking at the mem_fn tr1 proposal and noticed that argN_types were not mentioned. Was it simply because no one so far wanted it? Also, just to complement Marcus's use case, here is a real-world (simplified) use-case that my co-worker is encountering. ---------------------------------------------------------------------- template <typename BaseClassType> class ClassPool { public : void addClass(const std::string &key, BaseClassType *instance) { m_objectMap[key] = instance; } template <typename MemFnType> void executeMemberFunction(const std::string &key, MemFnType memFn) { //here is where we need the class type of the member fn typedef MemFnType::ClassType DerivedType; //we need to dynamic cast to the derived type so we can call //the member function on it typename DerivedType *derivedObject = dynamic_cast< DerivedType *>(m_objectMap[key]); //call the member function memFn(derivedObject); } std::map<std::string, BaseClassType *> m_objectMap; }; class BaseClass { }; class DerivedClass : public BaseClass { void someFunction() {}; }; void main() { ClassPool<BaseClass> classPool; classPool.addClass("SomeObject",new DerivedClass); classPool.executeMemberFunction("SomeObject",boost::mem_fn(someFunction)); }

Piyo wrote:
Peter Dimov wrote:
I'm somewhat reluctant to introduce features into boost::mem_fn since std::tr1::mem_fn and the upcoming std::mem_fn don't/won't have them. If you start using ::argN_type, you won't be able to switch to std::mem_fn once it becomes available. Of course if this is not a concern for the Boost community we can easily add the typedefs and the arity.
Hi Peter,
Several questions: - when C++0x gets published and when compilers are fully tr1 compliant, do you see boost::mem_fn (and the rest of the tr1 overlap) go away from boost?
Once std::mem_fn is widely available, there'll be no reason to use boost::mem_fn, except for old compilers. When the list of Boost-supported compilers no longer includes a compiler that doesn't have a std::mem_fn, boost/mem_fn.hpp can be reduced to: #include <functional> namespace boost { using std::mem_fn; }
- I was also interested into the rationale why it was omitted also. I was looking at the mem_fn tr1 proposal and noticed that argN_types were not mentioned. Was it simply because no one so far wanted it?
Lack of demand is one reason. Another is that mem_fn has a first argument that cannot be expressed as a typedef. There are probably others.
participants (3)
-
Marcus Lindblom
-
Peter Dimov
-
Piyo