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

troy d. straszheim troy at resophonic.com
Mon Nov 2 16:08:34 CET 2009


Ravi wrote:
> On Saturday 31 October 2009 01:24:16 troy d. straszheim wrote:
>> I take it that you have a use-case where it is difficult to specify
>>
>>    as<R(A1,A2)>(thing)
>>
>> and easy to specify
>>
>>    as<mpl::vector<R, A1, A2> >(thing)
>>
>> Could you elaborate?
> 
> I have some code that takes member function pointers of the form
>   R Obj::*( A1, A2, A3, ..., An )
> and converts them to a function object Q with the following signature:
>   Rnew Q( Obj&, B1, B2, ..., Bn )
> where
>   Rnew = result_conversion_metafunction<R>::type
>   Bi = arg_conversion_metafunction<Ai>::type
> and Q is exposed via boost.python as a member of Obj. 
>
> For example, Ai could be a fixed-point number, with Bi being a double so that 
> the python side does not know anything about fixed-point numbers. 

I gather that custom converters aren't preferred because:

1.  It is a hassle to talk directly to the underlying raw PyObject 
pointers and manage storage in the converter methods

2.  The converted type still leaks out to python in docstrings

(Both effects are visible in the custom string example: 
http://www.boost.org/doc/libs/1_40_0/libs/python/doc/v2/faq.html#custom_string)

Are there others?  Or am I completely off?

 > An instance
> of Q would convert eh floating point numbers passed from the python side into 
> fixed-point numbers, call the member function, and convert the returned value 
> to a double for use on the python side.
> 
> For these "converters", metafunctions from boost.function_types are used to 
> obtain the mpl::vector specifying result type and argument types. Extending 
> the technique above to function objects which take Obj* as their first 
> argument, I have a protocol which relies on the presence of a typedef called 
> 'components' in the function object so that I can use the converter when 
> exposing via boost.python:
> 
> struct my_functor {
>   typedef mpl::vector<R, Obj*, A1, A2, A3, A4> components;
>   R operator()( Obj*, A1, A2, A3, A4 ) { ... }
> };

To be sure I'm following you, correct me:

* for each member function signature that you wrap, you have a matching 
my_functor that calls it
* my_functor does nothing but call the member function it wraps
* my_converter<my_functor>::type does the conversion from Rnew (B1, B2, 
... Bn) to R (A1, A2, ...An) and calls my_functor.

Have I got it?

It is all very interesting, and to a certain degree duplicates some 
functionality in detail/caller.hpp.  How do you generate these 
my_functors...   preprocessor?  fusion?

I'm wondering if there isn't motivation here to cleanly integrate a 
general facility for additional c++-side type conversions.  The 
following came to mind, which imitates a function type style that 
boost::proto uses extensively:

   struct hidden_type;  // python shouldn't see this at all

   struct int_2_hidden  // converts python-side 'int' to hidden
   {
     typedef hidden_type result_type;

     hidden_type operator()(int) const;
   };

   // fnobj takes a hidden, doesn't know it is wrapped in python
   struct fnobj {
     typedef void result_type;
     void operator()(float, hidden_type);
   }; 	

   def("myfunctor", as<void(float, int_to_hidden(int))>(fnobj()));

where int_to_hidden(int) is a function type (not a function call, but it 
later becomes a function call), indicating that what python passes 
should be converted to int, then the int converted to hidden_type via an 
instance of int_to_hidden, then the hidden_type passed to the underlying 
instance of fnobj.

I realize this doesn't involve using the mpl::vectors you've already 
calculated, just throwing it out there.

> // my_converter uses the components typedef
> typedef typename my_converter<my_functor>::type Q;

so Q could have a nested typedef (note I say Rnew, not R):

  typedef mpl::vector<Rnew, Obj*, B1, B2, B3, B4> components;

or use that in combination with function_types to synthesize

  typedef Rnew(Obj*, B1, B2, B3, B4) signature;

> Q q;
> class_<Obj,...>( "Obj" )
>   .def( "my_func", q )
>   ;

-t




More information about the Cplusplus-sig mailing list