目前支持的C++特性
Classes
Constructors and destructors
Virtual functions
Public inheritance (including multiple inheritance)
Static functions
Function and method overloading
Operator overloading for many standard operators
References
Templates (including specialization and member templates)
Pointers to members
Namespaces
Default parameters
Smart pointers
目前还不支持的特性
作为一条铁律,最好不要将swig用到C++源文件上,只用swig来处理C++头文件
If a C++ class does not declare any explicit constructor, SWIG will automatically generate a wrapper for one.
If a C++ class does not declare an explicit copy constructor, SWIG will automatically generate a wrapper for one if the %copyctor is used.
If a C++ class does not declare an explicit destructor, SWIG will automatically generate a wrapper for one
A default constructor is not created if a class already defines a constructor with arguments.
Default constructors are not generated for classes with pure virtual methods or for classes that inherit from an abstract class, but don’t provide definitions for all of the pure methods.
A default constructor is not created unless all base classes support a default constructor.
Default constructors and implicit destructors are not created if a class defines them in a private or protected section.
Default constructors and implicit destructors are not created if any base class defines a non-public default constructor or destructor.
除了以上条件会影响构造函数和析枸函数的执行,还可以人为的使用指令来控制构造函数和析枸函数的封装
%nodefaultctor Foo; // Disable the default constructor for class Foo.
class Foo { // No default constructor is generated, unless one is declared
...
};
class Bar { // A default constructor is generated, if possible
...
};
%nodefaultdtor Foo; // Disable the implicit/default destructor for class Foo.
class Foo { // No destructor is generated, unless one is declared
...
};
如果嫌弃一个一个的指定麻烦还可以全局的进行限定
%nodefaultctor; // Disable creation of default constructors
class Foo { // No default constructor is generated, unless one is declared
...
};
class Bar {
public:
Bar(); // The default constructor is generated, since one is declared
};
%clearnodefaultctor; // Enable the creation of default constructors again
当swig进行封装之后可能会出错时, swig将不会对其进行封装
比如说:当一个构造函数被声明为保护类型属性时,swig将不会对其进行封装
class Foo {
protected:
Foo(); // Not wrapped.
public:
...
};
使用immutable对只读变量进行标记
class List {
public:
...
%immutable;
int length;
%mutable;
...
};
当然如果嫌麻烦可以使用更加明确的指定方式
%immutable List::length;
...
class List {
...
int length; // Immutable by above directive
...
};
The %naturalvar directive is a macro for, and hence equivalent to, %feature(“naturalvar”). It can be used as follows:
// All List variables will use const List& typemaps
%naturalvar List;
// Only Foo::myList will use const List& typemaps
%naturalvar Foo::myList;
struct Foo {
List myList;
};
// All non-primitive types will use const reference typemaps
%naturalvar;
It is generally a good idea to use this feature globally as the reference typemaps have extra NULL checking compared to the pointer typemaps. A pointer can be NULL, whereas a reference
cannot,
The naturalvar behavior can also be turned on as a global setting via the -naturalvar commandline option or the module mode option, %module(naturalvar=1). However, any use of
%feature(“naturalvar”) will override the global setting.
当有默认参数时,swig会为每个参数都新生成一个封装函数,如果需要封装的类中存在大量的默认参数,这样会导致封装之后的包非常的大,可以使用compactdefaultargs功能标记,添加之后该接口的所有默认参数处理会别合并到一起进行处理,能有效的缩小封装之后包的大小。
%feature("compactdefaultargs") Foo::bar;
class Foo {
public:
void bar(int x, int y = 3, int z = 4);
};
因为模板类只有在C++编译的时候才会展开,所以仅仅依照源码swig并不能得知要封装那种类型的的模板类,因此必须指定T类型之后才能对其进行封装。这个时候就可以借助rename来指定T了,具体使用方式如下:
将模板类具体化之后再通过rename修改别名,这个时候swig就能按照具体类进行封装了
%rename(intList) List<int>; // Rename to a suitable identifier
class List<int> {
private:
int *data;
int nitems;
int maxitems;
public:
List(int max);
~List();
void append(int obj);
int length();
int get(int n);
};
同时swig可以支持直接对模板进行操作,这时就需要借助%template指令了
需要注意这时的template有顺序要求,模板必须在指令之前才行,否则就会报错退出
template<class T> class List { ... };
%template(intList) List<int>;
List<Integer> = List<int>
%template(intList) List<int>;
typedef int Integer;
...
void foo(List<Integer> *x);
类型支持使用typedef重定义,但是模板绝对不允许,如果使用typedef重定义模板会导致出错
typedef List<int> ListOfInt;
%template(intList) List<int>; // ok
%template(intList) ListOfInt; // illegal - Syntax error
模板函数的封装
同样可以使用template指令来处理模板函数
// Function template
template<class T> T max(T a, T b) { return a > b ? a : b; }
// Make some different versions of this function
%template(maxint) max<int>;
%template(maxdouble) max<double>;
// 同样支持foo的模板重载
template<class T> void foo(T x) { };
template<class T> void foo(T x, T y) { };
%template(foo) foo<int>;
默认参数的函数模板
template <typename T, int max=100>
class ector {
};
%template(intvec) ector<int>; // OK
%template(vec1000) ector<int, 1000>; // OK
当函数是类的成员函数时,这时需要在类内进行模板封装
class Foo {
public:
template<class T> void bar(T x, T y) { ... };
...
%template(barint) bar<int>;
%template(bardouble) bar<double>;
};
如果类已经定义过了只能通过extend来进行扩展了
class Foo {
public:
template<class T> void bar(T x, T y) { ... };
...
};
...
%extend Foo {
%template(barint) bar<int>;
%template(bardouble) bar<double>;
};
或者使用C++的方式简化扩展的方式
class Foo {
public:
template<class T> void bar(T x, T y) { ... };
...
};
...
%template(bari) Foo::bar<int>;
%template(bard) Foo::bar<double>;
命名空间作为C++的一项基础功能,在swig支持的很好,但是如果不使用指令控制swig遇到一些比较棘手的问题还是会直接报错,比如默认情况下两个命名空间中有相同的类时,swig将无法区分两个类,因为swig的默认处理是将所有的命名空间的种类型都完全暴露出来,因为目标语言中可能没有明明空间这个概念(go语言也是后期才添加上的)
类重命名
%feature("nspace") MyWorld::Material::Future;
// %nspace MyWorld::Wrapping::Future; // %nspace is a macro for %feature("nspace")
// 在go语言中多个命名空间类重名,目前版本只能通过重命名来进行使用
%rename("Future1") MyWorld::Wrapping::Future;
namespace MyWorld {
namespace Material {
class Future {
};
}
namespace Wrapping {
class Future {
};
}
}
模板重命名
namespace Space {
%rename(bbb) ABC::aaa(T t); // 能够匹配但是优先级低于 ccc
%rename(ccc) ABC<Space::XYZ>::aaa(Space::XYZ t);// 能够匹配优先级高于 bbb
%rename(ddd) ABC<Space::XYZ>::aaa(XYZ t); // will not match
}
namespace Space {
class XYZ {};
template<typename T> struct ABC {
void aaa(T t) {}
};
}
%template(ABCXYZ) Space::ABC<Space::XYZ>;
异常处理需要借助catches指令,该指令后面需要跟需要捕获的错误列表;
%catches(Error1, Error2, ...) Foo::bar(); 说明需要捕获所有的异常,…代表说明要捕获任何其他可能的异常
struct EBase { virtual ~EBase(); };
struct Error1 : EBase { };
struct Error2 : EBase { };
struct Error3 : EBase { };
struct Error4 : EBase { };
%catches(Error1, Error2, ...) Foo::bar();
%catches(EBase) Foo::blah();
class Foo {
public:
...
void bar();
void blah() throw(Error1, Error2, Error3, Error4);
...
};
swig起初只是为了能够在目标语言中去调用C/C++语言,代理使得在C或者C++中反向调用目标语言也成为可能
SWIG’s primary goal is to make it possible to call C/C++ code from a target language, however, the director feature enables the reverse. While there isn’t simple direct support for calling target
language code from C, the director feature makes this possible.
通过设置directors可以让swig实现对回调函数的封装,设置之后swig会在对应的目标语言中生成目标语言的回调函数封装
%feature("director") BinaryOp;
%inline %{
struct BinaryOp {
virtual int handle(int a, int b) = 0;
virtual ~BinaryOp() {}
};
%}
支持初始化列表
支持部分模板
支持decltype类型推断,但是只是单个变量的推断,不支持对表达式的推断
支持部分lambda表达式,但是并不完全
支持新的函数定义形式
struct SomeStruct {
auto FuncName(int x, int y) -> int;
};
auto square(float a, float b) -> decltype(a);
初始化列表
增强型枚举类型
enum class MyEnum : unsigned int;
功能标记是swig用来控制一些数据生成特性的标记。
比如正常情况下siwg是不会生成copy构造函数的,但是如果你想生成copy构造函数可以通过feature进行指定
%copyctor List;
class List {
public:
List();
};
这个功能是1.32版本之后才添加上的,因此在1.32版本之前如果想生成copy构造函数的封装只能手动进行重命名才能实现
class Foo {
public:
Foo();
%name(CopyFoo) Foo(const Foo &);
...
};