[C++-sig] Re: IntWrapper.hpp in indexing_suite

Raoul Gough RaoulGough at yahoo.co.uk
Sat Oct 11 13:14:14 CEST 2003


"Niall Douglas" <s_sourceforge at nedprod.com> writes:

> Firstly, let me confirm I have this right:
>
> IntWrapper is converted into an int by bpl using the operator 
> boost::shared_ptr<IntWrapper>() const yes? Or is it the 
> implicitly_convertible? If it is the latter, why do we need the 
> shared_ptr<> operator?

I've used IntWrapper in a number of different test cases, and ISTR one
of them needed a conversion to shared pointer. I suspect that test
didn't make it into the CVS, so the shared pointer conversion is
currently redundant.

>
> Anyway I came up with the below by basically following the 
> testlinear.cpp example but unfortunately it complains "TypeError: No 
> to_python (by-value) converter found for C++ type: class 
> boost::python::indexing::iterator_pair<class CArrayMember<class 
> std::basic_string<char,struct std::char_traits<char>,class 
> std::allocator<char> > > *>". The code I used was:
>
>>>> from TestCArrays import *
>>>> a=MyList()
>>>> b=a.getData()
>
> I don't get why it's failing to find the conversion with mine whereas 
> it works with the test :(

I don't think the shared pointer conversion has anything to do with
this. The really important bit is this:

  boost::python::class_<IntWrapper> ("IntWrapper", boost::python::init<int>())
    .def ("increment", &IntWrapper::increment)
    .def ("__repr__", repr)
    .def ("__cmp__", compare)
    ;

which turns IntWrapper into a Python class, with enough support to
convert it to a string and compare two IntWrapper objects. There is
also an implicit conversion from int, which means that code like this
will work:

>>> v.append (IntWrapper(43))  # OK
>>> v.append (44)              # Also OK - implicit conversion

>
> Any help much appreciated.
>
> Cheers,
> Niall
>
> --- cut ---
> #include <boost/python.hpp>
> #include <boost/python/suite/indexing/container_suite.hpp>
> #include <boost/python/suite/indexing/iterator_pair.hpp>
> #include <boost/python/suite/indexing/container_proxy.hpp>
> #include <string>
>
> class MyList
> {
> 	std::string *array;
> public:
> 	MyList();
> 	std::string *getData() { return array; }
> };
>
> MyList::MyList()
> {
> 	static std::string data[]={ std::string("Niall"),
> 								std::string("is"),
> 								std::string("a"),
> 								std::string("teapot")
> 								};
> 	arrayÚta;
> }
>
> template<class T> class CArrayMember : public T
> {
> public:
> 	CArrayMember() : T() { }
> 	CArrayMember(const CArrayMember &o) : T(o) { }
> 	explicit CArrayMember(const T &o) : T(o) { }
> 	operator boost::shared_ptr<CArrayMember>() const
> 	{
> 		return boost::shared_ptr<CArrayMember>(new CArrayMember(*this));
> 	}
> };
>
> typedef 
> boost::python::indexing::iterator_pair<CArrayMember<std::string> *> 
> MyListCArray;
>
> MyListCArray MyList_getArray(MyList &l)
> {
> 	CArrayMember<std::string> 
> *data=static_cast<CArrayMember<std::string> *>(l.getData());

Wow. This is almost certainly undefined behaviour.

> 	return 
> boost::python::indexing::iterator_pair<CArrayMember<std::string> *>
> 		(data, data+100000); // Issue if l is near the 4Gb mark
> }

The bounds checking code will still be compiled, of course, so lying
about the bound doesn't actually gain you anything (unless you have no
way of figuring out the real bound). You should be able to provide the
correct bound without too much trouble in this example.

>
> BOOST_PYTHON_MODULE(TestCArrays)
> {
> 	boost::python::implicitly_convertible<std::string, 
> CArrayMember<std::string> >();
>
> 	boost::python::class_< MyListCArray, 
> boost::noncopyable>("MyListCArray", 
> 		boost::python::init<CArrayMember<std::string> *, 
> CArrayMember<std::string> *>())
> 		.def(boost::python::indexing::container_suite< MyListCArray >());
>
>     boost::python::class_< MyList, boost::noncopyable >("MyList")
> 		.def("getData", &MyList_getArray)
> 		;
> }

OK, so CArrayMember<std::string> is-a std::string. You still haven't
exposed it to Python though. You will need something like this:

class_<CArrayMember<std::string>, bases<std::string> >
   ("CArrayMember_string");

I don't know exactly what else you'll have to do here - maybe define
implicit conversions to/from std::string, maybe make it no_init. The
container suite doesn't attempt to expose the container's value type
to Python - it assumes that you will do that yourself. I would suggest
first trying to get CArrayMember<...> working in Python before trying
to expose a container of CArrayMembers.

-- 
Raoul Gough.
(setq dabbrev-case-fold-search nil)





More information about the Cplusplus-sig mailing list