python和基类虚函数的迭代器

Boost::python and iterators from base class virtual functions

本文关键字:迭代器 函数 基类 python      更新时间:2023-10-16

所以我试图写一个基类来处理包装std::vector的类,我已经开始定义__iter__函数。我的第一种方法,也是我希望使用的方法,是在基类中使用begin()和end()函数。这样做可以很好地编译,但是当我在python中运行代码时,我得到一个类似于以下错误:

Boost.Python。ArgumentError:

中的Python参数类型

Container.__iter__(容器)

不匹配c++签名:

__iter__ (python boost:::: back_reference> std::allocator>>>&>)

可以使用

测试以下示例扩展
from test import *
c = Container()
for i in range(10):
    c.append(K(str(i)))
for i in c:
    print i
样本扩展:

#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T> 
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
    typedef typename T::value_type V;
    typedef typename T::iterator iter;
    virtual T& get_vector()=0;
public:
    virtual ~stl_iter() {}
    virtual void append(V item) {
        get_vector().push_back(item);
    }
    virtual iter begin() {
        return get_vector().begin();
    }
    virtual iter end() {
        return get_vector().end();
    }
};
class K {
    std::string val;
public:
    K(std::string s) : val(s) {}
    std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
    vK items;
protected:
    vK& get_vector() { return items; }
public:
    // Works if I uncomment these
    //vK::iterator begin() { return get_vector().begin(); }
    //vK::iterator end() { return get_vector().end(); }

public:
    virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
    using namespace boost::python;
    class_<K, pK>("K", init<std::string>())
        .def("__str__", &K::get_val)
        ;
    class_<Container, pContainer>("Container")
        .def("append", &Container::append)
        .def("__iter__", range(&Container::begin, &Container::end))
        ;
}

答案其实很简单:让容器表现得像一个stl容器,然后使用boost的iterator<>()函数而不是range()

要做到这一点,我必须使stl_iter中的类型公开,并将它们重命名为value_typeiterator

这里是更新后的c++代码。

#include <memory>
#include <vector>
#include <string>
#include <boost/python.hpp>
template<class T> 
T* get_pointer(std::shared_ptr<T> const& p) { return p.get(); }
template<class T>
class stl_iter {
protected:
    virtual T& get_vector()=0;
public:
    // Next two lines changed, and made public
    typedef typename T::value_type value_type;
    typedef typename T::iterator iterator;
    virtual ~stl_iter() {}
    virtual void append(value_type item) {
        get_vector().push_back(item);
    }
    virtual iterator begin() {
        return get_vector().begin();
    }
    virtual iterator end() {
        return get_vector().end();
    }
};
class K {
    std::string val;
public:
    K(std::string s) : val(s) {}
    std::string get_val() const { return val; }
};
typedef std::shared_ptr<K> pK;
typedef std::vector<pK> vK;
class Container : public stl_iter<vK> {
    vK items;
protected:
    vK& get_vector() { return items; }
public:
    virtual ~Container() {}
};
typedef std::shared_ptr<Container> pContainer;
typedef std::vector<pContainer> vContainer;
BOOST_PYTHON_MODULE_INIT(test) {
    using namespace boost::python;
    class_<K, pK>("K", init<std::string>())
        .def("__str__", &K::get_val)
        ;
    class_<Container, pContainer>("Container")
        .def("append", &Container::append)
        // Use iterator() instead of range()
        .def("__iter__", iterator<Container>())
        ;
}

range()也可以很好地使用,但底层迭代器无论如何都应该支持STL语义,下面是示例:

...
.def("__iter__"
     , range<return_value_policy<copy_non_const_reference> >(
           &my_sequence<heavy>::begin
         , &my_sequence<heavy>::end))