Creating boost :: python :: range accepting ... a boost :: range

I have a C ++ class that provides collections by providing functions that return ranges using boost::range .

To export this class in python using boost::python , I use the boost::python::range function, which can take two parameters: class member functions that return the beginning and end of collection iterators.

I want to avoid manually writing start / end pairs for each collection, as I already provide a range. But I can’t write a wrapper over boost :: python :: range, which takes a member function that returns a range as an argument. Any ideas? (I actually have more than one class that is templatized, so the template function taking the address of the member function of the template class as a template parameter will not work, my compiler said)

I will accept a C ++ 0x solution if it is compiled with g ++ - 4.6.

edit: code example: let's say I have this class:

 struct A { std::vector<int> c; typedef boost::sub_range<std::vector<int> > c_range; c_range getc() { return c; } }; 

To create a Python iterator from the getc method, I now add these two member functions to class A:

 c_range::iterator c_begin() { return getc().begin(); } c_range::iterator c_end() { return getc().end(); } 

and then set them as follows:

 boost::python::class_<A>("A") .def("getc", boost::python::range(&A::c_begin, &A::c_end)); 

Is there a way to write directly something like:

 .def("getc", pyrange(&A::getc)); 

and avoid the need to write c_begin and c_end ?

+4
source share
1 answer

The solution was to use a more general form of a range with four template parameters: create begin / end accessors as boost::bind 'ed objects, and then specify the Target template range parameter. For constant iterators, this code satisfies my needs:

 namespace py = boost::python template <class T, class Return> struct range_accessor { typedef Return (T::*RA ) () const; static typename Return::const_iterator begin(RA ra, const T& t) { return (t.*ra)().begin(); } static typename Return::const_iterator end(RA ra, const T& t) { return (t.*ra)().end(); } static py::object pyrange(RA ra) { auto b = boost::bind(&range_accessor::begin, ra, _1); auto e = boost::bind(&range_accessor::end, ra, _1); return py::range< boost::python::objects::default_iterator_call_policies, T> // the "Target" parameter, which can // not be deduced from a bind object (b,e); } }; template <class T, class Return> py::object pyrange(Return (T::*ra ) () const) { return range_accessor<T, Return>::pyrange(ra); } 

Edit: A slightly more compact solution using the definition of the internal structure inside the structure:

 template <class T, class Return> py::object pyrange(Return (T::*ra) () const) { typedef Return (T::*RA ) () const; struct accessor { static typename Return::const_iterator begin(RA ra, const T& t) { return (t.*ra)().begin(); } static typename Return::const_iterator end(RA ra, const T& t) { return (t.*ra)().end(); } }; return py::range<boost::python::objects::default_iterator_call_policies, T> (boost::bind(&accessor::begin, ra, _1), boost::bind(&accessor::end, ra, _1)); } 
+4
source

Source: https://habr.com/ru/post/1346105/


All Articles