gpt4 book ai didi

python - 如何使用 SWIG 使 C++ 类可从 Python 迭代?

转载 作者:太空狗 更新时间:2023-10-29 21:16:20 27 4
gpt4 key购买 nike

我有一个 C++ 类 Collection管理 std::vector<Element> (类(class)的私有(private)成员)。

在 C++ 中,我可以使用 begin() 遍历 vector 和 end()迭代器(这只是 vector 的迭代器的类型定义)如:

Collection col;
for (Collection::const_iterator itr = col.begin(); itr != col.end(); itr++)
{
std::cout << itr->get() << std::endl;
}

现在我想用 Python 做类似的事情:

import example
el = example.Element()
el.set(5)
col = example.Collection()
col.add(el)
for e in col:
print e.get()

但这会导致:

TypeError: 'Collection' object is not iterable

我无法以生成 __iter__ 的方式配置 SWIG (我认为这是它唯一需要的东西)对于 Python Collection类(class)。我应该怎么做?

这是我的代码:

example.h:

#include <vector>

class Element
{
public:
Element();
~Element();

int get() const;
void set(const int var);

private:
int variable_;
};

class Collection
{
public:
Collection();
~Collection();

void add(const Element& element);

typedef std::vector<Element> tElements;

// iterators
typedef tElements::iterator iterator;
typedef tElements::const_iterator const_iterator;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;

private:
tElements elements_;
};

示例.cpp:

#include "example.h"

Element::Element() {}

Element::~Element() {}

int Element::get() const
{
return variable_;
}

void Element::set(const int var)
{
variable_ = var;
}

Collection::Collection() : elements_() {}

Collection::~Collection() {}

void Collection::add(const Element& element)
{
elements_.push_back(element);
}

Collection::iterator Collection::begin()
{
return elements_.begin();
}

Collection::const_iterator Collection::begin() const
{
return elements_.begin();
}

Collection::iterator Collection::end()
{
return elements_.end();
}

Collection::const_iterator Collection::end() const
{
return elements_.end();
}

例子.i:

%module example
%{
#include "example.h"
%}

// I've tried to add this, but that generates a whole
// other class, that is not what I want.
// %include "std_vector.i"
// %template(ElementVector) std::vector<Element>;

// I've also tried to %extend the class (which I think is what I want,
// but I cannot figure out with what to extend it with)

// Include the header file with above prototypes
%include "example.h"

编译:

swig -python -c++ -o example_wrap.cpp example.i
g++ -fPIC -c example.cpp example_wrap.cpp -I/usr/include/python2.6
g++ -shared example.o example_wrap.o -o _example.so

最佳答案

灵感来自最后一个例子:https://stackoverflow.com/a/8828454/3613373 .我提出了一种略有不同的方法,它不使用变量来检查 StopIterator 异常状态。

它也只使用 begin()结束 end() Collection 的迭代器无需公开(制作 public ) std::vector<Element>本身。

例子.i:

%module example
%{
#include "example.h"
%}

%inline %{
class StopIterator {};
class Iterator {
public:
Iterator(Collection::iterator _cur, Collection::iterator _end) : cur(_cur), end(_end) {}
Iterator* __iter__()
{
return this;
}
Collection::iterator cur;
Collection::iterator end;
};
%}

%include "example.h"

%include "exception.i"
%exception Iterator::next {
try
{
$action // calls %extend function next() below
}
catch (StopIterator)
{
PyErr_SetString(PyExc_StopIteration, "End of iterator");
return NULL;
}
}

%extend Iterator
{
Element& next()
{
if ($self->cur != $self->end)
{
// dereference the iterator and return reference to the object,
// after that it increments the iterator
return *$self->cur++;
}
throw StopIterator();
}
}

%extend Collection {
Iterator __iter__()
{
// return a constructed Iterator object
return Iterator($self->begin(), $self->end());
}
};

唯一我想不通的是如何创建 Iterator 的模板化版本以一种我可以通过任何 Iterator<Collection, Element> 的方式无需重新定义 next()对于每个模板实例。欢迎提供解决方案;)

关于python - 如何使用 SWIG 使 C++ 类可从 Python 迭代?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35291053/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com