[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