我想包装一个C++例程,它返回一个std::map整数和指向C++类实例的指针.我无法与SWIG合作,并希望能提供任何帮助.我试图通过一个简单的例子将这个问题归结为其本质.
标题test.h定义如下:
/* File test.h */
#include <stdlib.h>
#include <stdio.h>
#include <map>
class Test {
private:
static int n;
int id;
public:
Test();
void printId();
};
std::map<int, Test*> get_tests(int num_tests);
Run Code Online (Sandbox Code Playgroud)
实现定义test.cpp如下:
/* File test.cpp */
#include "test.h"
std::map<int, Test*> get_tests(int num_tests) {
std::map<int, Test*> tests;
for (int i=0; i < num_tests; i++)
tests[i] = new Test();
return tests;
}
int Test::n = 0;
Test::Test() {
id = n;
n++;
}
void Test::printId() {
printf("Test ID = %d", id);
}
Run Code Online (Sandbox Code Playgroud)
我编写了一个SWIG接口文件test.i来尝试适应这个例程,这样我就可以std::map<int, Test*>在Python中返回一个字典:
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "test.h"
%}
%include <std_map.i>
%typemap(out) std::map<int, Test*> {
$result = PyDict_New();
int size = $1.size();
std::map<int, Test*>::iterator iter;
Test* test;
int count;
for (iter = $1.begin(); iter != $1.end(); ++iter) {
count = iter->first;
test = iter->second;
PyDict_SetItem($result, PyInt_FromLong(count),
SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, SWIG_POINTER_NEW | 0));
}
}
%include "test.h"
Run Code Online (Sandbox Code Playgroud)
我包装例程并编译SWIG生成的包装器代码,并将其作为共享库链接,如下所示:
> swig -python -c++ -o test_wrap.cpp test.i
> gcc -c test.cpp -o test.o -fpic -std=c++0x
> gcc -I/usr/include/python2.7 -c test_wrap.cpp -o test_wrap.o -fpic -std=c++0x
> g++ test_wrap.o test.o -o _test.so -shared -Wl,-soname,_test.so
Run Code Online (Sandbox Code Playgroud)
然后我希望能够在Python中执行以下操作:
import test
tests = test.get_tests(3)
print tests
for test in tests.values():
test.printId()
Run Code Online (Sandbox Code Playgroud)
example.py但是,如果我将其作为脚本运行,则会得到以下输出:
> python example.py
{0: <Swig Object of type 'Test *' at 0x7f056a7327e0>, 1: <Swig Object of type 'Test *' at
0x7f056a732750>, 2: <Swig Object of type 'Test *' at 0x7f056a7329f0>}
Traceback (most recent call last):
File "example.py", line 8, in <module>
test.printId()
AttributeError: 'SwigPyObject' object has no attribute 'printId'
Run Code Online (Sandbox Code Playgroud)
任何想法为什么我得到SwigPyObject实例作为输出,而不是SWIG代理Test?任何帮助将不胜感激!
因为它存在的问题是由SWIG提供的std_map.i中的默认行为引起的.它提供了尝试std::map合理包装所有用法的类型映射.
其中一个是干扰你自己的输出类型图,所以如果我们改变你的接口文件:
%module test
%{
#define SWIG_FILE_WITH_INIT
#include "test.h"
%}
%include <std_map.i>
%clear std::map<int, Test*>;
%typemap(out) std::map<int, Test*> {
$result = PyDict_New();
int size = $1.size();
std::map<int, Test*>::iterator iter;
Test* test;
int count;
for (iter = $1.begin(); iter != $1.end(); ++iter) {
count = iter->first;
test = iter->second;
PyObject *value = SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, 0);
PyDict_SetItem($result, PyInt_FromLong(count), value);
}
}
%include "test.h"
Run Code Online (Sandbox Code Playgroud)
那么你的例子有效.在%clear从std_map.i抑制默认typemaps,但保留定义本身.如果没有更多的挖掘,我不太清楚究竟导致问题的原因是什么,但是你可以使用%template默认行为,除非有充分的理由不这样做.
顺便说一下,你的电话:
SWIG_NewPointerObj(SWIG_as_voidptr(test), SWIGTYPE_p_Test, SWIG_POINTER_NEW | 0));
Run Code Online (Sandbox Code Playgroud)
可能没有做你想要的 - 它将指针的所有权转移到Python,这意味着一旦Python代理完成它就会调用delete你并在你的地图中留下一个悬空指针.
您还可以使用$descriptor以避免必须弄清楚SWIG的内部名称修改方案,因此它变为:
// No ownership, lookup descriptor:
SWIG_NewPointerObj(SWIG_as_voidptr(test), $descriptor(Test*), 0);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1033 次 |
| 最近记录: |