[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 03:44:38 CEST 2006


On 9/5/06, Alex Mohr <amohr at pixar.com> wrote:
> > Thanks Alex, this worked great.  I had to change the Py_INCREF to a
> > bp::incref but otherwise things are all good.
> >
> > But now I have a rather strange followup question.
> >
> > It seems that Boost.Python is doing some magic behind the scenes to
> > convert an object coming from C++ as a smart pointer whose wrapped
> > pointer is NULL into a Python "None".  The is great, and was a
> > wonderful surprise.  But now I need to find a way to make it happen in
> > the other direction.
> >
> > How does boost.python convert a parameter of "None" into an
> > object/smart_ptr to pass to C++?
>
> It happens in the from_python conversion.  It just checks for None and
> (I believe) default-constructs a the pointer object.  Is it the case
> that default-constructing one of your smart pointers does not produce
> the intended NULL?  It probably wouldn't be hard to add a customization
> (paralleling get_pointer and pointee) to boost python.  But in the
> meantime...

I will try to find this in the boost.python code and verify the behavior.

>
> > I need to find a way to call a C++ method like:
> >
> > void setObject(ptr<Base> obj);
> >
> > from Python and call it in Python as "setObject(None)" and instruct
> > boost.python to convert this into a call behind the scenes in C++ to:
> >
> > setObject(NullPtr);
> >
> > where "NullPtr" is a global const value defined by the library that is
> > used to signify a NULL shared pointer throughout the system.  (the
> > reason it needs something like this is a little complex, but it is not
> > my library so I can't change this part much.)
> >
> > Alternatively, I could probably make it work if I could get
> > boost.python to make a call like:
> >
> > setObject(ref_ptr<Base>(NULL) )
> >
> > as I think I could get the library to automatically convert
> > ref_ptr<Base>(NULL) into a NullPtr.
> >
> > Any ideas?
>
> I think you can do either version by registering your own rvalue
> from_python converters for all your pointer types.  You can do this in
> the def_visitor along with the to_python conversion we discussed earlier.
>
> Just replace the relevant bits below ("Deal with the "None" case") with
> whatever you want.
>
> Again, I'm just typing this so it may not compile, and no guarantees of
> course...

All I can say is "wow!!".  You seem to understand the conversion
process inside boost.python much more then I do.  I will give these
methods a try tomorrow.  I will need to alter them slightly since I am
not using the def_visitor method you outlined.  (I am using Py++ to
generate the bindings so it really doesn't take any more typing to
just have it put the registration calls in the right place).  I will
let you know how it goes.

As a side note, if you don't mind me asking, how did you learn so much
about how the conversion process works.  I have always had trouble
understanding the full process and am looking for any advice about how
to learn it better.  (did you learn from the code, the API reference,
the mailing list, other??)  If you ever have any time or interest and
wanted to contribute some to a little documentation effort I am
working on in my spare time, take a look at http://tinyurl.com/zb76h .

Thanks again.

-Allen


>
> 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;
>      }
> };
>
>
> Alex
> _______________________________________________
> 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