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

Alex Mohr amohr at pixar.com
Wed Sep 6 23:19:43 CEST 2006


> 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?

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



More information about the Cplusplus-sig mailing list