Boost logo

Boost Users :

Subject: [Boost-users] [python] Function objects in place of member functions
From: Ravi (lists_ravi_at_[hidden])
Date: 2009-10-10 11:58:46


Hello,
  If a free function 'func' has X* as its first argument, then, boost.python
allows it to be bound to a member function on the python side, i.e., the
following is legal:
  void func( X* x, arg1_t arg ) { ... }
  class_<X>( "X" ).def( "func", &func );

In order to use a function object in place of a free function, one must
specialize/overload
  boost::python::detail::get_signature
which, for some reason, does not account for function objects. Here's a very
simple example that works:

----------------------------------------------
#include <boost/mpl/vector.hpp>

struct X { int y; };

// Function object
struct Z { int operator()( X *x, int z ) { return z + x->y; } };

namespace boost { namespace python { namespace detail {
mpl::vector<int, X*, int> get_signature( Z&, X* )
  {return mpl::vector<int, X*, int>();}
}}}

#include <boost/python/class.hpp>
#include <boost/python/module.hpp>

BOOST_PYTHON_MODULE( mft ) {
  boost::python::class_<X>( "X" )
    .def( "z", Z() ).def_readwrite( "y", &X::y ); }
-------------------------------------------------

However, note that the overload of get_signature precedes the inclusion of the
boost.python headers, which is extremely inconvenient. However, if the headers
are moved to their proper location as in the following,

----------------------------------------------
#include <boost/mpl/vector.hpp>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>

struct X { int y; };

// Function object
struct Z { int operator()( X *x, int z ) { return z + x->y; } };

namespace boost { namespace python { namespace detail {
boost::mpl::vector<int, X*, int> get_signature( Z&, X* )
  {return boost::mpl::vector<int, X*, int>();}
}}}

BOOST_PYTHON_MODULE( mft ) {
  boost::python::class_<X>( "X" )
    .def( "z", Z() ).def_readwrite( "y", &X::y ); }
-------------------------------------------------

the compilation fails with the following error message (gcc 4.4.1 with boost
1.37 or 1.39):

$ g++ -Wall -shared -o mft.so memft.cc -lboost_python-mt -
I/usr/include/python2.6 -fPIC
In file included from memft.cc:1:
/usr/include/boost/python/class.hpp: In member function ‘void
boost::python::class_<T, X1, X2, X3>::def_impl(T*, const char*, Fn, const
Helper&, ...) [with T = X, Fn = Z, Helper =
boost::python::detail::def_helper<const char*,
boost::python::detail::not_specified, boost::python::detail::not_specified,
boost::python::detail::not_specified>, W = X, X1 =
boost::python::detail::not_specified, X2 =
boost::python::detail::not_specified, X3 =
boost::python::detail::not_specified]’:
/usr/include/boost/python/class.hpp:235: instantiated from
‘boost::python::class_<T, X1, X2, X3>& boost::python::class_<T, X1, X2,
X3>::def(const char*, F) [with F = Z, W = X, X1 =
boost::python::detail::not_specified, X2 =
boost::python::detail::not_specified, X3 =
boost::python::detail::not_specified]’
memft.cc:16: instantiated from here
/usr/include/boost/python/class.hpp:536: error: no matching function for call
to ‘get_signature(Z&, X*)’

Why is the overloaded get_signature not picked up when it is declared *after*
the inclusion of the headers?

The reason for using function objects is to change the argument types of a
member function of X as seen by python; for example, the functor would have an
argument type 'double' and would then internally convert the received 'double'
argument from the python side into some custom type prior to passing it to the
member function of X. In other words, the functor would act as a C++
equivalent of a python decorator.

Regards,
Ravi


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net