[C++-sig] Re: got stuck starting with boost.python
David Abrahams
dave at boost-consulting.com
Tue Nov 2 16:18:31 CET 2004
Chris Niekel <chris at niekel.net> writes:
> Hi,
>
> I just started with boost.python, and I'm already stuck.
> The C++ classes provide a 'readonly' view of the objects, and the user of
> these classes can't create the objects, they're created and destroyed by some
> friend-class (say, Manager).
>
> So, there's a class Entity
> {
> protected:
> Entity();
> ~Entity();
>
> std::string getId();
> ...
> };
>
> class Manager
> {
> public:
> std::map<std::string, Entity*> getEntityMap();
> ...
> }
>
> First problem was that the Entity destructor had to be public.
> So I changed that in the headerfile
> Q1: is there a better way to fix that?
Use boost::noncopyable when wrapping Entity.
> I've translated the getEntityMap into a getEntities, using a new function
> that creates a boost::python::list and walks through the map, adding the
> elements. That works now.
>
> What I want to do next is:
>
> class_<Entity, Entity*>("Entity", no_init)
> .def_readonly("id", &Entity::getId)
> ;
>
> That gives me a weird errors:
> /usr/people1/smf/include/boost-1_31/boost/python/data_members.hpp:285:
> conversion
> from `boost::is_member_pointer<const
> std::string&(Entity::*)()
> const>' to non-scalar type `boost::mpl::bool_<false>' requested
def_readonly only works on pointers-to-data-members. Try
^^^^
.add_property("id", &Entity::getId)
you may yet need to use a return value policy as in:
.add_property(
"id"
, make_function(
&Entity::getId
, return_value_policy<copy_const_reference>()))
> which I don't understand. So working around the problem, I
> .def("id", &Entity::getId)
> That also gives an error:
> boost/python/detail/invoke.hpp:89: no match
> for call to `(const
> boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<const
> std::string&>) (const std::basic_string<char,
> std::char_traits<char>,
> std::allocator<char> >&)'
>
> Also beyond my comprehension.
As the message says, you have to "specify a return value policy to wrap
functions returning const std::string&." I suggest you use
return_value_policy<copy_const_reference>
> If I do:
> .def("id", &Entity::getId, return_internal_reference<>())
> it compiles, but I get the runtime exception:
> TypeError: No Python class registered for C++ class std::string.
Right. You're not wrapping std::string with a class_<...> (and you
don't want to) so Boost.Python has no way of creating a python object
that refers to the referenced std::string.
> So I've now created an extra method in the Entity: const char*
> getIdCStr() which returns the id.c_str(). That sorta works.
> I can do in python: for i in getEntities(): print i.id()
>
> With .add_property("id", &Entity::getIdCStr) it works as I want it.
Why didn't you use add_property in the first place? I ask because it
speaks to a deficiency in the documentation.
> Q2: This requires me to add methods to the Entity class (there are
> several std::string attributes I need). Is there a more elegant way
> to solve this?
A free function taking an initial X& parameter always works just as
well as a member function of X.
HTH,
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com
More information about the Cplusplus-sig
mailing list