假设我有一个任意的非平凡类型A
,我可以为其编写类型图。特别是,假设我知道如何将std::strings
转换为A
,并且我将目标语言中的字符串打印到A
。我导入stl_vector.i
和%template(AVector) std::vector<A>;
。
SWIG中最快/最简单(甚至是'正确')的操作方法是使用void func(const std::vector<A>& vals)
的函数包装器,其中目标语言端的预期输入是字符串列表(例如{{在Python中1}}?除非我错了,否则Just Work™似乎没有(具体来说,在生成的包装器代码中我没有看到['a', 'qqq']
的类型映射代码)。
如果需要特定的目标语言来回答,那就说它是Python。我宁愿能够在一般情况下这样做,但是......
答案 0 :(得分:0)
假设我们有一个类似的头文件:
#ifndef TEST_H
#define TEST_H
#include <iostream>
#include <functional>
#include <iterator>
struct A {
A(const std::string& v) : val(v) {}
A(const A&) = default;
A() = default;
std::string val;
};
inline std::ostream& operator<<(std::ostream& in, const A& o) {
return in << o.val;
}
inline void run(const std::vector<A>& in) {
std::copy(in.begin(), in.end(), std::ostream_iterator<A>(std::cout, "\n"));
}
#endif
我们希望将其包装起来,以便可以使用字符串列表调用run
,或者可以互换地调用std::vector<A>
。
鉴于语言不可知论是一个明确的目标,实现这一目标的最佳方法是引入更多的C ++,以帮助进行某些类型的转换和过载。
我们最初可以用以下简单的方式包装头文件:
%module test
%include <std_vector.i>
%include <std_string.i>
%{
#include "test.h"
%}
%template(AVec) std::vector<A>;
%include "test.h"
这足以运行Python测试用例的前半部分:
import test
test.A("")
v1=test.AVec(2,test.A("testing"))
print type(v1)
test.run(v1)
# Here onwards needs some more work though...
v2=["hello", "world", "isn't", "this", "fun"]
print type(v2)
test.run(v2)
要开始使用此测试用例的后半部分,我们需要调整SWIG接口。我将通过在包装器内部添加一个函数以及利用SWIG的std::vector<std::string>
默认类型映射的重载来实现此目的。
添加:
%{
// Some glue to trivially convert types
std::vector<A> convert(const std::vector<std::string>& in) {
std::vector<A> ret;
std::copy(in.begin(), in.end(), std::back_inserter(ret));
return ret;
}
%}
%inline %{
// An overload.
void run(const std::vector<std::string>& in) {
run(convert(in));
}
%}
在初始SWIG界面的末尾,我们添加了一个有效的重载,只要目标语言对std::vector
有一个合适的理解。 (我检查的大多数似乎都是。)
对于SWIG版本,我测试了这个版本,运行SWIG本身并打开警告,发出了关于阴影过载的(虚假)警告。这个警告似乎是不正确的,因为生成的代码确实根据给定的参数选择了正确的重载。
在接口文件中使用添加了%inline
的重载是迄今为止最快/最简单的方法来启动和运行。它当然需要复制/转换开销和每个函数手动写入重载。使用类型映射执行此操作只需要编写单个类型映射,但很难以独立于目标语言的方式执行。