[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 21:17:12 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 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.

I am sorting through this code right now.  Am I missing something or
is there no documentation in the reference guide about how to register
a converter directly with the registry?

Additionally, I was looking at the documentation for
implicitly_convertible and I am wondering why I can't just use that in
my case.

I want to call:

setObject(ptr<Base> val)

with a NoneType.  And I have all my objects (ie. Base) wrapped and set
with held types of ref_ptr<>'s.  RefPtr's are implicitly convertible
to ptr<>'s, so If I register this with boost.python using:

  bp::implicitly_convertible< ret_ptr<Base>, ptr<Base> >();

Then shouldn't boost.python be able to convert NoneType -->
ref_ptr<Base> --> ptr<Base>  ?  From the documentation in
implicitly_convertible it seems like this should be the case.  But I
have to admit I have not found the place in the boost.python code
where it handles the case of taking a NoneType and automatically
converting it into a NULL smart pointer to start with.

-Allen

>
> Again, I'm just typing this so it may not compile, and no guarantees of
> course...
>
> 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