[C++-sig] Is there a way to automatically convert a smart_ptr to a held_type (try 2)

Allen Bierbaum abierbaum at gmail.com
Wed Sep 6 23:32:12 CEST 2006


On 9/6/06, Alex Mohr <amohr at pixar.com> wrote:
> > This code allowed the setObject(None) to work now.  Unfortunately it
> > broke the functionality that had been working where I could call
> > setObject(PythonObject).
> >
> > More details (extracted from above):
> >
> > I have:
> >
> > // set method
> > void setObject(ptr<Base> obj);
> >
> > // Implicit conversion for ref_ptr to ptr
> > bp::implicitly_convertible< ref_ptr<Base>, ptr<Base> );
> >
> > // From original e-mail: this works to automatically convert
> > // ptr<Base> returns into ref_ptr<Base> as the held type
> > bp::to_pyton_converter< ptr<Base>, ptr_to_python< ptr<Base> >()
> >
> > // Most recent discussion: way to get None from python as ptr<Base>
> > // - This works to let me pass None into wrapped setObject method
> > bp::converter::registry::insert(&convertible, &construct,
> > bp::type_id<ptr<Base> >());
> >
> > The problem is that now when I try to call something like this in python:
> >
> > new_obj = objtype.create()
> > setObject(None)
> > setObject(new_obj)
> >
> > Both of these calls to setObject try to convert the object to a
> > ptr<Base> using the manually registered converter.  The converter only
> > really knows how to deal with the conversion from a None type.  In the
> > case of a real object I just want boost.python to convert the held
> > type (ref_ptr<Base> ) into a ptr<Base> using the implicit conversion.
> >
> > How do I get this to work?  Can I have multiple converters registered
> > and if so how do I tell boost.python to only use the manually created
> > one for the NoneType?
>
>
> The rvalue converter should handle both cases.  In convertible, it
> checks if it is getting None -- if it is, it says yes, I can make a
> pointer.  If it gets something other than None, it says I can make a
> pointer iff I can get an lvalue pointer to the Pointee from the python
> object.  That's the code after the if.  It uses already registered
> lvalue converters to do this.
>
> The construct method has a similar structure -- in the None case (first
> part of if) it will just placement new a default-constructed pointer.
> In the else part of the if, it will placement new a pointer pointing to
> the c++ instance.
>
> Can you tell me what's going on in convertible and construct when you do
> this?

The problem for me was that the rvalue converter when passed a
non-None could not do the placement new created of the ptr<Base>
because the constructor is protected.  The library I am wrapping
requires all objects to be created using static factory methods:

ref_ptr<Base> obj = Class.create()

So there is something going on in the implicit conversion for the
smart pointers that just handles things better.

I ended up getting the code to work though by making it so the rvalue
convertible method return NULL if p != NonType.  This ends up meaning
that the rvalue converter is only used in the case of passing None,
but it works for me now.

Thanks for your help.  I will let you know if anything else crops up
but I think I am starting to understand this part of boost.python much
better now so hopefully I will be able to fix it myself. :)

Thanks,
Allen

>
>  > setObject(new_obj)
>
> Alex
>
>
>  >> template <class Ptr>
>  >> struct smart_ptr_from_python {
>  >>      typedef typename boost::python::pointee<Ptr>::type Pointee;
>  >>      smart_ptr_from_python() {
>  >>          converter::registry::insert(&convertible, &construct,
>  >>                                      type_id<Ptr>());
>  >>      }
>  >>    private:
>  >>      static void *convertible(PyObject *p) {
>  >>          // can always produce a pointer from None.
>  >>          if (p == Py_None)
>  >>              return p;
>  >>          // Otherwise, we can do it if we can get the pointee out.
>  >>          void *result = converter::get_lvalue_from_python
>  >>              (p, converter::registered<Pointee>::converters);
>  >>          return result;
>  >>      }
>  >>
>  >>      static void construct(PyObject* source, converter::
>  >>                            rvalue_from_python_stage1_data* data) {
>  >>          void* const storage =
>  >>              ((converter::rvalue_from_python_storage<Ptr>*)data)->
>  >>              storage.bytes;
>  >>          // Deal with the "None" case.
>  >>          if (data->convertible == source)
>  >>              new (storage) Ptr();  // Or whatever you want.
>  >>          else
>  >>              new (storage)
>  >> Ptr(static_cast<Pointee*>(data->convertible));
>  >>          data->convertible = storage;
>  >>      }
>  >> };
> _______________________________________________
> C++-sig mailing list
> C++-sig at python.org
> http://mail.python.org/mailman/listinfo/c++-sig
>



More information about the Cplusplus-sig mailing list