使用boost::python导出C++数组/STL容器的方法 | 及其他函数和类的方法

使用boost::python 导出c++的函数和类都比较容易,可以参见boost::python模块的tutorial

问题:

但是如何导出C++的数组并不是一个容易的事情,恰逢项目需要使用,于是研究了一番。

解决记录:

  1. 先上boost官网的boost::python模块的tutorial,没有发现这方面的介绍和样例。
  2. 然后找[Frequently Asked Questions (FAQs)],发现有介绍 wrap的方法,该方法的示例可以在scitbx模块中找到示例(感觉boost::python和scitbx的编写者是同一群人)。
  3. 找到了,就先照着做吧,从GitHub上下载了scitbx,看了下其给出的两个参考cpp。琢磨了一会儿,发现实现方式是在是太麻烦了,不符合奥卡姆剃刀原则。心想,这个回答非常老了(2002/03/10),过了十几年了,现在肯定有新的解决方案吧?
  4. 于是重新搜索,找了半天之后,在Stack Overflow找到了可用的解决方案,直接在C++中定义boost::python::list即可。

直接上代码:

下面的例子非常清晰地给出了python list <--> stl vector/list 之间的转换,可以轻松地扩展到其他STL容器。

巧的是,该回答的作者表示这个方法是在cctbx/scitbx中参考得到的,哈哈,觉得自己应该再仔细研究一下scitbx =.=。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <vector>
#include <boost/python.hpp>
#include <boost/python/object.hpp>
#include <boost/python/stl_iterator.hpp>

namespace bpy = boost::python;

namespace fm {

template <typename Container>
bpy::list stl2py(const Container& vec) {
typedef typename Container::value_type T;
bpy::list lst;
std::for_each(vec.begin(), vec.end(), [&](const T& t) { lst.append(t); });
return lst;
}

template <typename Container>
void py2stl(const bpy::list& lst, Container& vec) {
typedef typename Container::value_type T;
bpy::stl_input_iterator<T> beg(lst), end;
std::for_each(beg, end, [&](const T& t) { vec.push_back(t); });
}

//采用python的list作为输入,然后输出python的list
bpy::list sum(const bpy::list& lhs, const bpy::list& rhs) {
std::vector<double> lhsv;
py2stl(lhs, lhsv);

std::vector<double> rhsv;
py2stl(rhs, rhsv);

std::vector<double> result(lhsv.size(), 0.0);
for (int i = 0; i < lhsv.size(); ++i) {
result[i] = lhsv[i] + rhsv[i];
}
return stl2py(result);
}

} // namespace fm

BOOST_PYTHON_MODULE(fm)
{
bpy::def("sum", &fm::sum);
}

用于自查

简单(省略)记录目前自己所使用的boost::python导出方法,便于自查,包括函数,类,python元组tuple,python list:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <python.h>

#include "windows.h"

#include <list>

#include <boost/progress.hpp>
#include <boost/timer.hpp>
#include <boost/foreach.hpp>
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/wrapper.hpp>
#include <boost/python/call.hpp>
namespace bp = boost::python;

class volumeInfo
{
public:
volumeInfo():cutvolume(-1)anglesum(0) {}
void clear(){cutvolume=0;}
float cutvolume;
bp::list cutanglerange;
};

static volumeInfo remove_cylinder(int x, int y, int z, int x2, int y2, int z2, int r,
int dx, int dy, int dz, int ox, int oy, int oz)
{
volumeInfo info;

std::list<std::pair<float, float>> cut_angle;
setcylinder_getCutVolume(&p1, &p2, r, -1, 0, volumebox, &dp, cut_angle);

for (auto iter=cut_angle.begin(); iter!=cut_angle.end(); ++iter)
{
info.cutanglerange.append(bp::make_tuple(iter->first, iter->second));
info.anglesum += (iter->second - iter->first);
}
return info;
}

//导出至python模块
BOOST_PYTHON_MODULE(vxCut)
{
bp::class_<volumeInfo>("volumeInfo")
.def(bp::init<volumeInfo>())
.def("clear", &volumeInfo::clear)
.def_readwrite("cutvolume", &volumeInfo::cutvolume)
.def_readwrite("cutanglerange", &volumeInfo::cutanglerange)
.def_readwrite("anglesum", &volumeInfo::anglesum)
;

bp::def("remove_cylinder", remove_cylinder);
}
Title - Artist
0:00