[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