On Thu, Feb 6, 2014 at 1:53 PM, Gary Oberbrunner <ga...@genarts.com> wrote:
> I have a function returning a bp::list, so:
>
> static bp::list EXTget_params(Container *g)
> {
>   bp::list param_list;
>   int n_params = g->n_params;
>   for (int i = 0; i < n_params; i++) {
>     // Need this boost::ref to put a ref to the param into the list
>     // rather than a param itself.  (That would cause it to try to copy the
>     // param, but it's listed as noncopyable so it would just get a 
> TypeError.)
>     param_list.append(bp::ref(g->params[i]));
>   }
>   return param_list;
> }
>
> Note that the Param is noncopyable.  Its lifetime is managed by Container.  
> The above works, except each time it runs it makes new bp::ref objects, which 
> don't compare equal to each other:
>
>  param1 = g.get_params()[0]
>  param2 = g.get_params()[0] // should be same as param1
>  if param1 == param2:
>     print "Success!"
>
> It doesn't print success, because the bp::ref objects are different, and 
> don't have operator== to compare their referents (at least that's my guess 
> about what's going on).  Is there something else I can use instead of bp::ref 
> here that will cause the list items to "point to" the same param each time I 
> call get_params()?
>

bp::ref isn't actually a kind of object; it's just a hint to
Boost.Python that it shouldn't deep-copy your object when converting
it to Python.  The problem is simply that because you don't have a
Python __eq__ operator defined, you're comparing the pointers of the
Python objects that hold your C++ objects (mostly what you'd guessed).
 And when you create a new Python object from a C++ object in general,
there's no easy way for Boost.Python to get at some
previously-Python-ized instance of that same object so it can just
return the same Python object again.

I think there are two ways to address this:

 - You can wrap the things you're putting in the list in such a way
that Boost.Python has them hold a pointer to their own Python selves.
Then, when they're converted back to Python, I believe Boost.Python
will just use that internal pointer.  But this will only work if all
the things in the list were originally constructed by calling their
constructors in Python (otherwise those internal pointers can't get
initialized), and I'm not positive it will all work even then.
There's more information on how to do that here:
http://www.boost.org/doc/libs/1_53_0/libs/python/doc/v2/class.html#HeldType

 - Add a __eq__/__ne__ overrides to the class of things you're putting
in the list, with an implementation that compares C++ pointers, not
Python pointers.  This is almost certainly much easier, but it's a
little less "complete" as a solution, in the sense that you'll still
be getting different Python objects back for the same C++ object (so
while "param2 == param1" will succeed, "param1 is param2" will still
fail).

Good luck!

Jim
_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
https://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to