From garyo at genarts.com Thu Feb 6 19:53:19 2014 From: garyo at genarts.com (Gary Oberbrunner) Date: Thu, 6 Feb 2014 13:53:19 -0500 (EST) Subject: [C++-sig] returning list of class pointers that compare equal In-Reply-To: <954838218.5072156.1391712774075.JavaMail.root@genarts.com> Message-ID: <1966764786.5072178.1391712799533.JavaMail.root@genarts.com> 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()? Thanks; -- Gary Oberbrunner From talljimbo at gmail.com Thu Feb 6 20:11:16 2014 From: talljimbo at gmail.com (Jim Bosch) Date: Thu, 6 Feb 2014 14:11:16 -0500 Subject: [C++-sig] returning list of class pointers that compare equal In-Reply-To: <1966764786.5072178.1391712799533.JavaMail.root@genarts.com> References: <954838218.5072156.1391712774075.JavaMail.root@genarts.com> <1966764786.5072178.1391712799533.JavaMail.root@genarts.com> Message-ID: On Thu, Feb 6, 2014 at 1:53 PM, Gary Oberbrunner 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 From garyo at genarts.com Thu Feb 6 20:43:56 2014 From: garyo at genarts.com (Gary Oberbrunner) Date: Thu, 6 Feb 2014 14:43:56 -0500 (EST) Subject: [C++-sig] returning list of class pointers that compare equal In-Reply-To: Message-ID: <1812318449.5074611.1391715836394.JavaMail.root@genarts.com> ----- Original Message ----- > From: "Jim Bosch" ... > - 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). This is very helpful! That's OK about "is" not working, I think (though true, a little odd.) Can I override __hash__ too, so set membership works correctly? Also do I need to override __ne__; I think not? For the record, here's what I did. Defined a comparison function: static bool params_equal(Param &left, Param &right) { return &left == &right; } and then in the exposer: Param_exposer.def("__eq__", ¶ms_equal); -- Gary Oberbrunner From talljimbo at gmail.com Thu Feb 6 20:51:59 2014 From: talljimbo at gmail.com (Jim Bosch) Date: Thu, 6 Feb 2014 14:51:59 -0500 Subject: [C++-sig] returning list of class pointers that compare equal In-Reply-To: <1812318449.5074611.1391715836394.JavaMail.root@genarts.com> References: <1812318449.5074611.1391715836394.JavaMail.root@genarts.com> Message-ID: On Thu, Feb 6, 2014 at 2:43 PM, Gary Oberbrunner wrote: > ----- Original Message ----- >> From: "Jim Bosch" > ... >> - 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). > > This is very helpful! That's OK about "is" not working, I think (though true, a little odd.) > > Can I override __hash__ too, so set membership works correctly? Also do I need to override __ne__; I think not? > > For the record, here's what I did. Defined a comparison function: > > static bool params_equal(Param &left, Param &right) > { > return &left == &right; > } > > and then in the exposer: > > Param_exposer.def("__eq__", ¶ms_equal); > That should be fine, as long as you don't care about what happens when you try to compare a Param to something else entirely (idiomatic Python behavior would be to return False; this implementation will likely raise an exception). You should be able to override __hash__ in much the same way, and I'd recommend checking to see if __ne__ works as expected before assuming you don't need to implement it yourself; I don't recall Python's behavior in this case, but I think it has a tendency not to define most operators implicitly. Jim From garyo at genarts.com Thu Feb 6 21:07:59 2014 From: garyo at genarts.com (Gary Oberbrunner) Date: Thu, 6 Feb 2014 15:07:59 -0500 (EST) Subject: [C++-sig] returning list of class pointers that compare equal In-Reply-To: Message-ID: <141759033.5075064.1391717279403.JavaMail.root@genarts.com> ----- Original Message ----- > From: "Jim Bosch" > To: "Development of Python/C++ integration" > Sent: Thursday, February 6, 2014 2:51:59 PM > Subject: Re: [C++-sig] returning list of class pointers that compare equal > > On Thu, Feb 6, 2014 at 2:43 PM, Gary Oberbrunner > wrote: > > ----- Original Message ----- > >> From: "Jim Bosch" > > ... > >> - 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). > > > > This is very helpful! That's OK about "is" not working, I think > > (though true, a little odd.) > > > > Can I override __hash__ too, so set membership works correctly? > > Also do I need to override __ne__; I think not? > > > > For the record, here's what I did. Defined a comparison function: > > > > static bool params_equal(Param &left, Param &right) > > { > > return &left == &right; > > } > > > > and then in the exposer: > > > > Param_exposer.def("__eq__", ¶ms_equal); > > That should be fine, as long as you don't care about what happens > when > you try to compare a Param to something else entirely (idiomatic > Python behavior would be to return False; this implementation will > likely raise an exception). I thought about that; for some reason the above works (no exception). It never calls my params_equal code; it must have some kind of fallback. > You should be able to override __hash__ in much the same way, and I'd > recommend checking to see if __ne__ works as expected before assuming > you don't need to implement it yourself; I don't recall Python's > behavior in this case, but I think it has a tendency not to define > most operators implicitly. Just tested it, and as you suspect, indeed I do need __ne__, otherwise param1 != param2 returns True when it should return False. -- Gary Oberbrunner From Martin.Franzke at t-systems.com Tue Feb 11 15:05:09 2014 From: Martin.Franzke at t-systems.com (Martin.Franzke at t-systems.com) Date: Tue, 11 Feb 2014 15:05:09 +0100 Subject: [C++-sig] boost python lambda support Message-ID: <5F36B451F397CC4AAEB701F6E14011F0F10412D636@HE113565.emea1.cds.t-internal.com> Hi being an enthusiastic user of boost python, I often missed the possibility to use function objects, see http://www.boost.org/doc/libs/1_55_0/libs/python/todo.html#wrapping-function-objects. Now I succeeded in a workaround to do so. The code below allows to use function objects, lambdas and std::function<> with arbitrary signature. It should work for c++11 compliant compilers (declspec must be implemented), I tested it with Visual Studio 2012 and gcc4.8.1. For the latter the code must be included prior to #include . Up to now it didn't break my existing code and the definitions with lambdas work as expected. Regards Martin ------------------------------------------------------------------------------------------ #ifndef BOOST_NO_CXX11_DECLTYPE # include # include # include # include # include # include # include namespace boost { namespace python { namespace detail { template struct fun_sign { typedef T type; }; template struct fun_sign< T, typename enable_if< mpl::greater< mpl::size, mpl::size_t<1> > >::type > { typedef typename mpl::erase< T, typename mpl::next< typename mpl::begin< T >::type >::type >::type type; }; template typename disable_if, typename fun_sign::types>::type>::type get_signature(T, void* = 0) { return typename fun_sign::types>::type(); } }}} //#endif -------------- next part -------------- An embedded and charset-unspecified text was scrubbed... Name: boost_python_lambda_support.txt URL: