[C++-sig] [python] Function objects in place of member functions

Ravi lists_ravi at lavabit.com
Sat Oct 10 17:58:46 CEST 2009


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



More information about the Cplusplus-sig mailing list