Поддерживает ли Boost Python функцию, возвращающую вектор, по ref или значению? - PullRequest
1 голос
/ 13 июля 2010

Я новичок в Python, я посмотрел на Boost Python, и это выглядит очень впечатляет. Однако, проходя через введение, я не могу найти любые примеры, где вектор объектов возвращается как список / кортежи python.

Т.е. взять этот пример, я хочу показать класс X, Cont и все его функции. критический бит возвращает вектор X или строк в python

  class X {};

   class Cont {

       .....
       // how can this be exposed using boost python
       const std::vector<X>&  const_ref_x_vec() const { return x_vec_;}
       std::vector<X> value_x_vec() const { return x_vec;}

       const std::vector<std::string>& const_ref_str_vec() const { return str_vec_;}
       std::vector<std::string> value_str_vec() const { return str_vec_; }

       ...
   private:
       std::vector<X> x_vec_;
       std::vector<std::string> str_vec_;
  };

Моя собственная бесплодная попытка разоблачить такие функции, как const_ref_x_vec (), value_x_vec () и т. д. просто приводят к ошибкам компиляции.

от поисков вокруг Я не видел ни одного примера, поддерживающего возвращаемые векторы по значению или ссылке. Это возможно даже с Boost Python? есть ли обходные пути? я должен использовать SWIG для этого случая?

Любая помощь приветствуется.

Avtar

Ответы [ 2 ]

9 голосов
/ 09 ноября 2010

Причина автозапуска была по существу правильной, но код был более сложным, чем необходимо.

vector_indexing_suite может сделать всю работу за вас:

class_< std::vector<X> >("VectorOfX")
    .def(vector_indexing_suite< std::vector<X> >() )
    ;

Существует также map_indexing_suite .

2 голосов
/ 31 июля 2010

Поскольку вы не можете предоставлять типы шаблонов для Python, вы должны явно предоставлять каждый вид вектора, который вы хотите использовать, например, это из моего кода:

Общий шаблон для упаковки вещей:

namespace bp = boost::python;

inline void IndexError(){
    PyErr_SetString(PyExc_IndexError, "Index out of range");
    bp::throw_error_already_set();
}

template<class T>
struct vec_item{
    typedef typename T::value_type V;
    static V& get(T& x, int i){
        static V nothing;
        if(i < 0) i += x.size();
        if(i >= 0 && i < int(x.size())) return x[i];
        IndexError();
        return nothing;
    }
    static void set(T& x, int i, V const& v){
        if(i < 0) i += x.size();
        if(i >= 0 && i < int(x.size())) x[i] = v;
        else IndexError();
    }
    static void del(T& x, int i){
        if(i < 0) i += x.size();
        if(i >= 0 && i < int(x.size())) x.erase(x.begin() + i);
        else IndexError();
    }
    static void add(T& x, V const& v){
        x.push_back(v);
    }
};

Тогда для каждого контейнера:

    // STL Vectors:
    // LineVec
    bp::class_< std::vector< Line > >("LineVec")
        .def("__len__", &std::vector< Line >::size)
        .def("clear", &std::vector< Line >::clear)
        .def("append", &vec_item< std::vector< Line > >::add, 
              bp::with_custodian_and_ward<1, 2>()) // let container keep value
        .def("__getitem__", &vec_item< std::vector< Line > >::get,
             bp::return_value_policy<bp::copy_non_const_reference>())
        .def("__setitem__", &vec_item< std::vector< Line > >::set,
             bp::with_custodian_and_ward<1,2>()) // to let container keep value
        .def("__delitem__", &vec_item< std::vector< Line > >::del)
        .def("__iter__", bp::iterator< std::vector< Line > >())
    ;
    // ... 

Аналогичный подход возможен для std::map. При написании этой статьи я использовал большую помощь из wiki.python.org .

...