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


_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to