11.2 Typemap规范
本章主要描述%typemap指令的行为。
11.2.1 定义typemap
新的typemap使用%typemap指令定义。一般格式如下(以[…]包含的部分是可选的):
%typemap(method [, modifiers]) typelist code ;
method用于指定定义什么样的typemap,它是个简单的名字。这些名字通常像这样:”in”,”out”, 或 “argout”。这些方法的目的后面会解释。
modifiers是一个可选的以逗号分隔,name="value"形式的列表。它们给typemap提供额外的信息,一般都是目标语言特有的,被称为typemap的属性(attibutes)。
typelist是typemap要匹配的C++数据类型模式的列表。一般形式描述如下:
typelist : typepattern [, typepattern, typepattern, ... ] ;typepattern : type [ (parms) ]| type name [ (parms) ]| ( typelist ) [ (parms) ]
每种类型模式可以是:简单类型、简单类型和参数名、多参数typemap类型的列表。除此之外,每个类型模式都可以参数化成暂存变量列表(params)。其用途后面也会简短描述。
code指定typemap的代码段。通常都是C/C++代码,像C#和Java这样的静态类型目标语言,代码段可能包含目标语言代码。可以采用以下几种形式:
code : { ... }| " ... "| %{ ... %}
注意,预处理器会扩展{}界定符号里面的代码,另外两种格式的界定符号不做扩展,参考预处理和typemap了解细节。下面是一些有效的typemap写法:
/* Typemap with extra argument name */%typemap(in) int nonnegative {...}/* Multiple types in one typemap */%typemap(in) int, short, long {$1 = SvIV($input);}/* Typemap with modifiers */%typemap(in,doc="integer") int "$1 = scm_to_int($input);";/* Typemap applied to patterns of multiple arguments */%typemap(in) (char *str, int len),(char *buffer, int size){$1 = PyString_AsString($input);$2 = PyString_Size($input);}/* Typemap with extra pattern parameters */%typemap(in, numinputs=0) int *output (int temp),long *output (long temp){$1 = &temp;}
11.2.2 Typemap作用域
Typemap一旦定义,跟在后面的所有声明都将使用这些规则。你可以在输入文件的需要的地方重新定义typemap。例如:
// typemap1%typemap(in) int {...}int fact(int); // typemap1int gcd(int x, int y); // typemap1// typemap2%typemap(in) int {...}int isprime(int); // typemap2
对%extend特征指令,typemap的作用域规则不太一样。%extend用来给结构或类定义定义新的声明。因为如此,它使用在结构或类定义处定义的 typemap。举个例子:
class Foo {...};%typemap(in) int {...}%extend Foo {int blah(int x); // typemap has no effect. Declaration is attached to Foo which// appears before the %typemap declaration.};
11.2.3 拷贝typemap
使用赋值操作可以拷贝typemap。例如:
%typemap(in) Integer = int;
或则:
%typemap(in) Integer, Number, int32_t = int;
一种类型一般会有一组不同的typemap来控制。例如:
%typemap(in) int { ... }%typemap(out) int { ... }%typemap(varin) int { ... }%typemap(varout) int { ... }
为了拷贝这些typemap到新的类型,可以使用%apply指令。例如:
%apply int { Integer }; // Copy all int typemaps to Integer%apply int { Integer, Number }; // Copy all int typemaps to both Integer and Number
%apply使用与%typemap一样的规则,例如:
%apply int *output { Integer *output }; // Typemap with name%apply (char *buf, int len) { (char *buffer, int size) }; // Multiple arguments
11.2.4 删除typemap
要删除一个typemap,可以简单地将其代码段设为空,例如:
%typemap(in) int; // Clears typemap for int%typemap(in) int, long, short; // Clears typemap for int, long, short%typemap(in) int *output;
%clear指令可以清除指定类型的所有typemap,例如:
%clear int; // Removes all types for int%clear int *output, long *output;
因为SWIG的默认行为是使用typemap定义的,清除基础数据类型如
int将会使该类型不可用,除非你在清除了后立马再定义一组新的typemap。
11.2.5 放置typemap
Typemap可以在全局作用域声明,也可以在C++命名空间、类声明等处。例如:
%typemap(in) int {...}namespace std {class string;%typemap(in) string {...}}class Bar {public:typedef const int & const_reference;%typemap(out) const_reference {...}};
当typemap出现在命名空间或类中时,它的影响一直作用到输入文件结尾。但是,typemap的作用域是局部的。因此,这段代码:
namespace std {class string;%typemap(in) string {...}}
就为std::string定义了typemap。你可能有如下代码:
namespace std {class string;%typemap(in) string { /* std::string */...}}namespace Foo {class string;%typemap(in) string { /* Foo::string */...}}
在这个例子里,有两个完全不同的typemap应用于不同的类型(std::string和Foo::string)。
为了让作用域工作,SWIG需要知道string定义在特殊的命名空间。在这个例子中,可以使用class string前置声明达此目的。
