делая повышение :: python :: диапазон принятия ... повышение :: диапазон - PullRequest
4 голосов
/ 31 марта 2011

У меня есть класс c ++, который предоставляет коллекции, предоставляя функции, возвращающие диапазоны, используя boost::range.

Чтобы экспортировать этот класс в python с boost::python, я использую функцию boost::python::range, котораяможет принимать два параметра: функции-члены класса, возвращающие итераторы начала и конца коллекции.

Я хочу избежать написания пар начала / конца вручную для каждой коллекции, так как я уже предоставляю диапазон.Но мне не удается написать обертку над boost :: python :: range, принимая в качестве аргумента функцию-член, возвращающую диапазон.Есть идеи?(На самом деле у меня есть несколько классов, которые шаблонизированы, поэтому функция шаблона, принимающая в качестве параметра шаблона адрес функции-члена класса шаблона, не будет работать, сказал мой компилятор)

Я примурешение c ++ 0x, если оно скомпилировано с g ++ - 4.6.

edit: пример кода в ответ на вопрос: скажем, у меня есть этот класс:

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

Для создания итератора Python из getc метод, я теперь добавляю эти две функции-члены в класс A:

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

и затем выставляю их так:

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

Есть ли способ написать что-то вроде:

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

и чтобы избежать необходимости писать c_begin и c_end?

1 Ответ

4 голосов
/ 01 апреля 2011

Решением было использование более общей формы range с четырьмя параметрами шаблона: создайте начальные / конечные средства доступа как boost::bind 'ed объекты, а затем укажите параметр шаблона Target для range.Для константных итераторов этот код удовлетворяет моим потребностям:

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);
}

Редактировать: немного более компактное решение, используя локальную структуру внутри определения функции:

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));
}
...