[pygccxml-development] wrapping pod struct with reference member variables
Brought to you by:
mbaas,
roman_yakovenko
From: Roman Y. <rom...@gm...> - 2009-01-20 05:59:44
|
On Tue, Jan 20, 2009 at 12:24 AM, <sit...@li...> wrote: > The attached message was received as a bounce, but either the bounce > format was not recognized, or no member addresses could be extracted > from it. This mailing list has been configured to send all > unrecognized bounce messages to the list administrator(s). Maik, for some reason your message was bounced. > ---------- Forwarded message ---------- > From: Maik Beckmann <bec...@go...> > To: pyg...@li... > Date: Mon, 19 Jan 2009 22:34:50 +0100 > Subject: wrapping pod struct with reference member variables > > Hi, > > I use structs with reference members for convenience naming in my code. For example > struct LookupTables{ > LookupTable& Fx,Fy,Fz; > }; > The ctor is omitted by intention to be able to use it like an POD > LookupTables lt = > { > forcesLookupTables[0], forcesLookupTables[1], forcesLookupTables[1] > }; Boost.Python don't like such structs - it cannot track the memory usage reliably. You also force your users to be aware of the memory management issue ( keep LookupTable alive, until LookupTables class instance is alive ) > = Hand written bpl code = > Wrapping this code with boost python is possible. > Consider this code > struct Refee { }; > struct Refer { Refee& refee; }; > The hand written written wrapper code looks like this > {{{ > namespace boost { namespace python { > struct no_default_ctor_policy : default_call_policies > { > static bool precall(PyObject*) > { > PyErr_SetString(PyExc_StandardError, "no default ctor"); > throw_error_already_set(); > } > }; > }} // ns boost::python > namespace { > void set_refee(Refer& refer, Refee& refee) > { refer.refee = refee; } > Refee get_refee(Refer& refer) > { return refer.refee; } > std::auto_ptr<Refer> make_refer(Refee* refee) > { > Refer tmp = { *refee }; > return std::auto_ptr<Refer>(new Refer(tmp)); > } > } //anonymous ns > BOOST_PYTHON_MODULE(pyExample) > { > bp::class_<Refee>("Refee"); > bp::class_<Refer>("Refer", bp::init<>()[bp::no_default_ctor_policy()]) > .def("__init__", bp::make_constructor(make_refer)) > .add_property("refee", get_refee, set_refee); > } > }}} > There are two tricks. > 1. Calling the default __init__(self) would cause an dangling reference. no_default_ctor_policy raises an error if someone call Refer() > 2. getter and setter are free functions, nothing special > This code > {{{ > from pyExample import Refer, Refee > refee = Refee() > #refer = Refer(r)# raises error > refer = Refer(refee) > }}} > works. > = pyplusplus = > py++ however, generates this (reformatted to make it a little shorter) > {{{ > struct Refer_wrapper : Refer, bp::wrapper< Refer > { > Refer_wrapper(Refer const & arg ): Refer( arg ) , bp::wrapper< Refer >() > { } > Refer_wrapper() : Refer(), bp::wrapper< Refer >() > { } > static ::Refee & get_refee( Refer& inst ) { > return inst.refee; > } > static void set_refee( Refer& inst, ::Refee & new_value ){ > inst.refee = new_value; > } > }; > BOOST_PYTHON_MODULE(pyExample){ > bp::class_< Refee >( "Refee" ); > { //::Refer > typedef bp::class_< Refer_wrapper > Refer_exposer_t; > Refer_exposer_t Refer_exposer = Refer_exposer_t( "Refer" ); > bp::scope Refer_scope( Refer_exposer ); > Refer_exposer.def( "get_refee" > , (::Refee & (*)( ::Refer & ))(&Refer_wrapper::get_refee) > , bp::return_value_policy< bp::copy_non_const_reference >() ); > Refer_exposer.def( "set_refee" > , (void (*)( ::Refer &,::Refee & ))(&Refer_wrapper::set_refee) ); > } > } > }}} > == Problems == > There are three problems: > 1. > The wrapper ctors are trouble. It's default construct breaks compilation, because there is no way it can proper initialize the members of the Refer. Refer lacks the ctor to do this (by intention, see above). > Wrapping isn't an option AFAICT. Obviously this is a bug. I will check it against current SVN ( both gccxml and Py++ ). > 2. The call policies for the __init__(self) are not altered You have a bug in the relevant code: > defctor = foo.operator(arg_types=[None]) defctor = foo.find_trivial_constructor() if defctor: .... > 3. A fake constructor (via bp::make_constructor) is needed > === regarding 1. === > Excluding all reference members stops wrapping. But then I have to write the getter/setter functions myself. > === regarding 2. === > I played around and it seems setting custom call policies > like > {{{ > Refer = mb.class_('Refer') > Refer.variables().exclude() > defctor = foo.operator(arg_types=[None]) > defctor.call_policies = call_policies.custom_call_policies("no_default_ctor_policy", "call_policies.hpp") > }}} > doesn't have an effect!? See my previous comment > === regarding 3. === > So far I didn't get how class_t.add_fake_constructors works. This function takes a calldef_t as argument. If I inject code via mb.add_declaration_code mb.free_function('make_refer') doesn't work because gccxml newer saw the code. Any hints how to construct a calldef_t after gccxml ran? You don't. Tweaking declarations tree is not a good idea. > As a workaround I added the code to the parsed header file and did > mb.class_('Refer').add_fake_constructors(mb.free_function('make_refer')) > which results in > {{{ > File "/usr/lib/python2.6/site-packages/pyplusplus/decl_wrappers/class_wrapper.py", line 210, in add_fake_constructors > self._fake_constructors.add( f ) > AttributeError: 'list' object has no attribute 'add > }}} This is a bug, which I fixed right now. Thanks for reporting. It seems that I always used\tested the other path :-). > I know doing mb.class_('Refer').exclude() and creating the wrapper code from the information in mb.class_('Refer') works (I did this for template class template member member functions), but I wonder what are the other means to teach py++ what I want. I am going to play with your example, stay turned :-) P.S. Please format a little the code, so it could be easier to read. Thanks -- Roman Yakovenko C++ Python language binding http://www.language-binding.net/ |