[C++-sig] [python] python + phoenix

troy d. straszheim troy at resophonic.com
Thu Oct 15 03:59:42 CEST 2009


Ravi wrote:
 >
 > I'd rather have something along the lines of
 >       .def< mpl::vector<void,T*,double> >("f1",f1)

I have something working.  There is still a bunch of stuff to iron out
yet.  I went with

   def("name", as<Signature>(callable));

where Signature is the signature with which callable will be called,
e.g.

   struct times_seven
   {
     template <typename T> struct result;

     template <typename Self, typename T>
     struct result<Self(T&)>  // annoying: reference
     {
       typedef T type;
     };

     template <typename T>
     T operator()(const T& t)
     {
       return t * 7;
     }
   };

   BOOST_PYTHON_MODULE( function_objects3_ext )
   {
     def("times_seven", as<int(int)>(times_seven()));
   }

the T& in the struct result is something I haven't yet sorted out, has
something to do with how I am constructing fusion sequences from the
converted python objects before calling fusion::invoke.  Anyhow, it
works:

   >>> times_seven(7)
   49

I thought that one might try to remove the necessity of having the
return type in the Signature and/or implementing the result_of
protocol, but maybe it is nice that they don't have to match:

   def("times_seven", as<double(int)>(times_seven()));

   >>> times_seven(7)
   49.0

boost::function still works, and doesn't require as<>:

   boost::function<int(int, int)> myplus = std::plus<int>();
   def("myplus", myplus);

and old-school function objects:

   def("otherplus", std::plus<int>())

I was surprised to find that it all plays nice with boost::phoenix:

   def("plus", as<int(int, int)>(arg1 + arg2));

   def("throw_if_gt_5",
       as<void(int)>(if_(arg1 > 5)
		    [ throw_(std::runtime_error("too big!!")) ]
		    .else_
		    [ std::cout << val("okay")                ]));

And boost::phoenix plays nice with shared_ptr, which plays nice with
boost::python:

   struct X { int x; };   typedef boost::shared_ptr<X> XPtr;

   class_<X, XPtr>("X")
     .def_readwrite("x", &X::x)
     .def("add7", as<void(X*)>  (arg1->*&X::x      += 7))
     .def("add8", as<void(XPtr)>(arg1->*&X::x      += 8))
     .def("add9", as<void(X&)>  (bind(&X::x, arg1) += 9))
   ;

the other little thing is overload resolution, for which I propose a
little helper function "unload" (underload? deload? resolve?  I dunno):

   void foo(int);
   void foo(double);

   def("foo", unload<void(int)>(foo));

Which is safer than

   def("foo", (void(*)(int)) foo);

and just as safe as, and less verbose than

   void(*fooint)(int) = foo;
   def("foo", fooint);

So that's where I'm at...  what do you make of that interface?

-t



More information about the Cplusplus-sig mailing list