目錄
- 12 自定義功能
- 12.1 用
處理異常%exception
- 12.1.1 C 代碼中的異常處理
- 12.1.2 用
longjmp()
- 12.1.3 處理 C++ 異常
- 12.1.4 變量的異常處理器
- 12.1.5 定義不同的異常處理器
- 12.1.6
的特殊變量%exception
- 12.1.7 使用 SWIG 異常庫
- 12.2 對象所有權與
%newobject
- 12.3 功能與
指令%feature
- 12.3.1 功能屬性
- 12.3.2 功能标志
- 12.3.3 清除功能
- 12.3.4 功能與預設參數
- 12.3.5 功能示例
- 12.1 用
In many cases, it is desirable to change the default wrapping of particular declarations in an interface. For example, you might want to provide hooks for catching C++ exceptions, add assertions, or provide hints to the underlying code generator. This chapter describes some of these customization techniques. First, a discussion of exception handling is presented. Then, a more general-purpose customization mechanism known as "features" is described.
在許多情況下,使用者希望更改接口檔案中特定聲明的預設包裝。例如,你可能想要提供鈎子來捕獲 C++ 異常,添加斷言或為底層代碼生成器提供提示。本章介紹其中一些自定義技術。首先,對異常處理進行了讨論。然後,描述了一種稱為“功能”的,更通用的自定義機制。
%exception
%exception
The
%exception
directive allows you to define a general purpose exception handler. For example, you can specify the following:
%exception
指令允許你定義通用異常處理程式。例如,你可以指定以下内容:
%exception {
try {
$action
}
catch (RangeError) {
... handle error ...
}
}
How the exception is handled depends on the target language, for example, Python:
異常的處理方式取決于目智語言,例如在 Python 中:
%exception {
try {
$action
}
catch (RangeError) {
PyErr_SetString(PyExc_IndexError, "index out-of-bounds");
SWIG_fail;
}
}
When defined, the code enclosed in braces is inserted directly into the low-level wrapper functions. The special variable
$action
is one of a few
%exception
special variables supported and gets replaced with the actual operation to be performed (a function call, method invocation, attribute access, etc.). An exception handler remains in effect until it is explicitly deleted. This is done by using either
%exception
or
%noexception
with no code. For example:
一旦定義,用大括号括起來的代碼直接插入到低級包裝器函數中。特殊變量是受支援的少數
$action
特殊變量之一,并被替換為要執行的實際操作(函數調用、方法調用、屬性通路等)。異常處理程式将一直有效,直到被明确删除。這可以通過
%exception
或
%exception
來完成,無須編寫代碼。例如:
%noexception
%exception; // Deletes any previously defined handler
Compatibility note: Previous versions of SWIG used a special directive
%except
for exception handling. That directive is deprecated--
%exception
provides the same functionality, but is substantially more flexible.
注意相容性:早期版本的 SWIG 使用特殊指令進行異常處理。該指令已被棄用——
%except
提供相同的功能,但實質上更為靈活。
%exception
C has no formal exception handling mechanism so there are several approaches that might be used. A somewhat common technique is to simply set a special error code. For example:
C 沒有正式的異常處理機制,是以可以使用幾種方法來實作。某種常見的技術是簡單地設定特殊的錯誤代碼。例如:
/* File : except.c */
static char error_message[256];
static int error_status = 0;
void throw_exception(char *msg) {
strncpy(error_message, msg, 256);
error_status = 1;
}
void clear_exception() {
error_status = 0;
}
char *check_exception() {
if (error_status)
return error_message;
else
return NULL;
}
To use these functions, functions simply call
throw_exception()
to indicate an error occurred. For example :
要使用這些函數,函數隻需調用 throw_exception()
來訓示發生了錯誤。例如 :
double inv(double x) {
if (x != 0)
return 1.0/x;
else {
throw_exception("Division by zero");
return 0;
}
}
To catch the exception, you can write a simple exception handler such as the following (shown for Perl5) :
要捕獲異常,你可以編寫一個簡單的異常處理程式,例如以下代碼(針對 Perl5):
%exception {
char *err;
clear_exception();
$action
if ((err = check_exception())) {
croak(err);
}
}
In this case, when an error occurs, it is translated into a Perl error. Each target language has its own approach to creating a runtime error/exception in and for Perl it is the
croak
method shown above.
在這種情況下,一旦錯誤發生,它将轉換為 Perl 錯誤。每種目智語言都有自己的方法來在其中建立運作時錯誤/異常,對于 Perl 來說,這是上面顯示的 croak
方法。
longjmp()
longjmp()
Exception handling can also be added to C code using the
<setjmp.h>
library. Here is a minimalistic implementation that relies on the C preprocessor :
也可以使用 <setjmp.h>
庫将異常處理添加到 C 代碼中。這是一個依賴 C 預處理器的簡約實作:
/* File : except.c
Just the declaration of a few global variables we're going to use */
#include <setjmp.h>
jmp_buf exception_buffer;
int exception_status;
/* File : except.h */
#include <setjmp.h>
extern jmp_buf exception_buffer;
extern int exception_status;
#define try if ((exception_status = setjmp(exception_buffer)) == 0)
#define catch(val) else if (exception_status == val)
#define throw(val) longjmp(exception_buffer, val)
#define finally else
/* Exception codes */
#define RangeError 1
#define DivisionByZero 2
#define OutOfMemory 3
Now, within a C program, you can do the following :
現在,在 C 程式中,你可以這樣做:
double inv(double x) {
if (x)
return 1.0/x;
else
throw(DivisionByZero);
}
Finally, to create a SWIG exception handler, write the following :
最終,如下可以建立一個 SWIG 異常處理器:
%{
#include "except.h"
%}
%exception {
try {
$action
} catch(RangeError) {
croak("Range Error");
} catch(DivisionByZero) {
croak("Division by zero");
} catch(OutOfMemory) {
croak("Out of memory");
} finally {
croak("Unknown exception");
}
}
Note: This implementation is only intended to illustrate the general idea. To make it work better, you'll need to modify it to handle nested
try
declarations.
注意:此實作僅用于說明一般想法。為了使其更好地工作,你需要對其進行修改以處理嵌套的 try
聲明。
Handling C++ exceptions is also straightforward. For example:
處理 C++ 異常也很簡單。例如:
%exception {
try {
$action
} catch(RangeError) {
croak("Range Error");
} catch(DivisionByZero) {
croak("Division by zero");
} catch(OutOfMemory) {
croak("Out of memory");
} catch(...) {
croak("Unknown exception");
}
}
The exception types need to be declared as classes elsewhere, possibly in a header file :
異常類型需要在其他地方聲明為類,可能是在頭檔案中:
class RangeError {};
class DivisionByZero {};
class OutOfMemory {};
By default all variables will ignore
%exception
, so it is effectively turned off for all variables wrappers. This applies to global variables, member variables and static member variables. The approach is certainly a logical one when wrapping variables in C. However, in C++, it is quite possible for an exception to be thrown while the variable is being assigned. To ensure
%exception
is used when wrapping variables, it needs to be 'turned on' using the
%allowexception
feature. Note that
%allowexception
is just a macro for
%feature("allowexcept")
, that is, it is a feature called
allowexcept
. Any variable which has this feature attached to it, will then use the
%exception
feature, but of course, only if there is a
%exception
attached to the variable in the first place. The
%allowexception
feature works like any other feature and so can be used globally or for selective variables.
預設情況下,所有變量都将忽略,是以對于所有變量包裝器均将其關閉。這适用于全局變量、成員變量和靜态成員變量。在用 C 包裝變量時,這種方法當然是合乎邏輯的。但是,在 C++ 中,很可能在配置設定變量時引發異常。為了確定在包裝變量時使用
%exception
,需要使用
%exception
功能将其
%allowexception
。請注意,
turned on
隻是
%allowexception
的宏,也就是說,它是一個名為
%feature("allowexcept")
的功能。任何具有此功能的變量都将使用
allowexcept
功能,但是,前提當然是首先要在變量上附加
%exception
。
%exception
功能與任何其他功能一樣工作,是以可以全局使用或用于選擇性變量。
%allowexception
%allowexception; // turn on globally
%allowexception Klass::MyVar; // turn on for a specific variable
%noallowexception Klass::MyVar; // turn off for a specific variable
%noallowexception; // turn off globally
By default, the
%exception
directive creates an exception handler that is used for all wrapper functions that follow it. Unless there is a well-defined (and simple) error handling mechanism in place, defining one universal exception handler may be unwieldy and result in excessive code bloat since the handler is inlined into each wrapper function.
To fix this, you can be more selective about how you use the
%exception
directive. One approach is to only place it around critical pieces of code. For example:
預設情況下,
%exception
指令建立一個異常處理程式,該異常處理程式用于其後的所有包裝函數。除非有一個定義明确(且簡單)的錯誤處理機制,否則定義一個通用異常處理程式可能會很麻煩,并且由于該處理程式被内聯到每個包裝器函數中,是以會導緻代碼過于膨脹。
為了解決這個問題,你可以更具選擇性地使用
指令。一種方法是僅将其放置在關鍵的代碼周圍。例如:
%exception
%exception {
... your exception handler ...
}
/* Define critical operations that can throw exceptions here */
%exception;
/* Define non-critical operations that don't throw exceptions */
More precise control over exception handling can be obtained by attaching an exception handler to specific declaration name. For example:
通過将異常處理程式附加到特定的聲明名稱,可以獲得對異常處理更精确的控制。例如:
%exception allocate {
try {
$action
}
catch (MemoryError) {
croak("Out of memory");
}
}
In this case, the exception handler is only attached to declarations named
allocate
. This would include both global and member functions. The names supplied to
%exception
follow the same rules as for
%rename
described in the section on Ambiguity resolution and renaming. For example, if you wanted to define an exception handler for a specific class, you might write this:
在這種情況下,異常處理程式僅附加到名為的聲明。這将包括全局和成員函數。提供給
allocate
的名稱遵循與消歧義和重命名一節中所述的
%exception
相同的規則。例如,如果你想為特定的類定義異常處理程式,則可以這樣編寫:
%rename
%exception Object::allocate {
try {
$action
}
catch (MemoryError) {
croak("Out of memory");
}
}
When a class prefix is supplied, the exception handler is applied to the corresponding declaration in the specified class as well as for identically named functions appearing in derived classes.
%exception
can even be used to pinpoint a precise declaration when overloading is used. For example:
提供類字首時,異常處理程式将應用于指定類中的相應聲明,以及派生類中出現的名稱相同的函數。
使用重載時,甚至可以使用
來精确定位聲明。例如:
%exception
%exception Object::allocate(int) {
try {
$action
}
catch (MemoryError) {
croak("Out of memory");
}
}
Attaching exceptions to specific declarations is a good way to reduce code bloat. It can also be a useful way to attach exceptions to specific parts of a header file. For example:
将異常附加到特定聲明是減少代碼膨脹的好方法。将異常附加到頭檔案的特定部分也是一種有用的方法。例如:
%module example
%{
#include "someheader.h"
%}
// Define a few exception handlers for specific declarations
%exception Object::allocate(int) {
try {
$action
}
catch (MemoryError) {
croak("Out of memory");
}
}
%exception Object::getitem {
try {
$action
}
catch (RangeError) {
croak("Index out of range");
}
}
...
// Read a raw header file
%include "someheader.h"
Compatibility note: The
%exception
directive replaces the functionality provided by the deprecated
except
typemap. The typemap would allow exceptions to be thrown in the target language based on the return type of a function and was intended to be a mechanism for pinpointing specific declarations. However, it never really worked that well and the new %exception directive is much better.
注意相容性:指令替換了不推薦使用的
%exception
類型映射提供的功能。類型映射将允許根據函數的傳回類型以目智語言抛出異常,并且該映射旨在成為一種精确定位特定聲明的機制。但是,它從來沒有真正奏效過,新的
except
指令要好得多。
%exception
%exception
%exception
%exception
directive supports a few special variables which are placeholders for code substitution. The following table shows the available special variables and details what the special variables are replaced with.
%exception
指令支援一些特殊變量,它們是代碼替換的占位符。下表顯示了可用的特殊變量,并詳細說明了用哪些特殊變量替換的變量。
| The actual operation to be performed (a function call, method invocation, variable access, etc.) |
---|---|
| The C/C++ symbol name for the function. |
| The symbol name used internally by SWIG |
| The extra mangling used in the symbol name for overloaded method. Expands to nothing if the wrapped method is not overloaded. |
| The language specific wrapper name (usually a C function name exported from the shared object/dll) |
| The fully qualified C/C++ declaration of the method being wrapped without the return type |
| The fully qualified C/C++ declaration of the method being wrapped including the return type |
| The parent class name (if any) for a method. |
| The target language parent class name (if any) for a method. |
The special variables are often used in situations where method calls are logged. Exactly which form of the method call needs logging is up to individual requirements, but the example code below shows all the possible expansions, plus how an exception message could be tailored to show the C++ method declaration:
特殊變量通常用于記錄方法調用的情況。究竟哪種形式的方法調用需要記錄取決于個人要求,但是下面的示例代碼顯示了所有可能的擴充,以及如何定制異常消息以顯示 C++ 方法聲明:
%exception Special::something {
log("symname: $symname");
log("overname: $overname");
log("wrapname: $wrapname");
log("decl: $decl");
log("fulldecl: $fulldecl");
try {
$action
}
catch (MemoryError) {
croak("Out of memory in $decl");
}
}
void log(const char *message);
struct Special {
void something(const char *c);
void something(int i);
};
Below shows the expansions for the 1st of the overloaded
something
wrapper methods for Perl:
下面顯示了 Perl 重載的 something
包裝器方法的第一種擴充:
log("symname: Special_something");
log("overname: __SWIG_0");
log("wrapname: _wrap_Special_something__SWIG_0");
log("decl: Special::something(char const *)");
log("fulldecl: void Special::something(char const *)");
try {
(arg1)->something((char const *)arg2);
}
catch (MemoryError) {
croak("Out of memory in Special::something(char const *)");
}
exception.i
library file provides support for creating language independent exceptions in your interfaces. To use it, simply put an "
%include exception.i
" in your interface file. This provides a function
SWIG_exception()
that can be used to raise common scripting language exceptions in a portable manner. For example :
庫檔案支援在接口檔案中建立獨立于語言的異常。要使用它,隻需在接口檔案中引入
exception.i
。這提供了一個函數
%include exception.i
,該函數可用于以可移植的方式引發常見的腳本語言異常。例如 :
SWIG_exception()
// Language independent exception handler
%include exception.i
%exception {
try {
$action
} catch(RangeError) {
SWIG_exception(SWIG_ValueError, "Range Error");
} catch(DivisionByZero) {
SWIG_exception(SWIG_DivisionByZero, "Division by zero");
} catch(OutOfMemory) {
SWIG_exception(SWIG_MemoryError, "Out of memory");
} catch(...) {
SWIG_exception(SWIG_RuntimeError, "Unknown exception");
}
}
As arguments,
SWIG_exception()
takes an error type code (an integer) and an error message string. The currently supported error types are :
作為參數, SWIG_exception()
采用錯誤類型代碼(整數)和錯誤消息字元串。目前支援的錯誤類型是:
SWIG_UnknownError
SWIG_IOError
SWIG_RuntimeError
SWIG_IndexError
SWIG_TypeError
SWIG_DivisionByZero
SWIG_OverflowError
SWIG_SyntaxError
SWIG_ValueError
SWIG_SystemError
SWIG_AttributeError
SWIG_MemoryError
SWIG_NullReferenceError
SWIG_exception()
function can also be used in typemaps.
SWIG_exception()
函數也可以用于類型映射。
%newobject
%newobject
A common problem in some applications is managing proper ownership of objects. For example, consider a function like this:
在某些應用程式中,一個常見的問題是正确地管理對象的所有權。例如,考慮如下函數:
Foo *blah() {
Foo *f = new Foo();
return f;
}
If you wrap the function
blah()
, SWIG has no idea that the return value is a newly allocated object. As a result, the resulting extension module may produce a memory leak (SWIG is conservative and will never delete objects unless it knows for certain that the returned object was newly created).
To fix this, you can provide an extra hint to the code generator using the
%newobject
directive. For example:
如果包裝函數
blah()
,SWIG 不知道傳回值是新配置設定的對象。結果,生成的擴充子產品可能會産生記憶體洩漏(SWIG 是保守的,除非确定可以肯定傳回的對象是新建立的,否則從不删除對象)。
為了解決這個問題,你可以使用
指令為代碼生成器提供額外的提示。例如:
%newobject
%newobject blah;
Foo *blah();
%newobject
works exactly like
%rename
and
%exception
. In other words, you can attach it to class members and parameterized declarations as before. For example:
的工作方式與
%newobject
和
%rename
完全相同。換句話說,你可以像以前一樣将其附加到類成員和參數化聲明中。例如:
%exception
%newobject ::blah(); // Only applies to global blah
%newobject Object::blah(int, double); // Only blah(int, double) in Object
%newobject *::copy; // Copy method in all classes
...
When
%newobject
is supplied, many language modules will arrange to take ownership of the return value. This allows the value to be automatically garbage-collected when it is no longer in use. However, this depends entirely on the target language (a language module may also choose to ignore the
%newobject
directive).
Closely related to
%newobject
is a special typemap. The
newfree
typemap can be used to deallocate a newly allocated return value. It is only available on methods for which
%newobject
has been applied and is commonly used to clean-up string results. For example:
當提供時,許多語言子產品将安排擷取傳回值的所有權。這樣就可以在不再使用該值時自動對其進行垃圾回收。但是,這完全取決于目智語言(語言子產品也可以選擇忽略
%newobject
%newobject
指令)。
與
密切相關的是一個特殊的類型映射。
%newobject
類型映射可用于釋放新配置設定的傳回值。它僅在應用了
newfree
的方法上可用,并且通常用于清理字元串結果。例如:
%newobject
%typemap(newfree) char * "free($1);";
...
%newobject strdup;
...
char *strdup(const char *s);
In this case, the result of the function is a string in the target language. Since this string is a copy of the original result, the data returned by
strdup()
is no longer needed. The "newfree" typemap in the example simply releases this memory.
As a complement to the
%newobject
, from SWIG 1.3.28, you can use the
%delobject
directive. For example, if you have two methods, one to create objects and one to destroy them, you can use:
在這種情況下,函數的結果是目智語言中的字元串。由于該字元串是原始結果的副本,是以不再需要傳回的資料。示例中的
strdup()
newfree
類型映射僅釋放該記憶體。
作為對 SWIG 1.3.28 中
的補充,你可以使用
%newobject
指令。例如,如果你有兩種方法,一種用于建立對象,另一種用于銷毀它們,則可以使用:
%delobject
%newobject create_foo;
%delobject destroy_foo;
...
Foo *create_foo();
void destroy_foo(Foo *foo);
or in a member method as:
或者在成員方法中作為:
%delobject Foo::destroy;
class Foo {
public:
void destroy() { delete this;}
private:
~Foo();
};
%delobject
instructs SWIG that the first argument passed to the method will be destroyed, and therefore, the target language should not attempt to deallocate it twice. This is similar to use the
DISOWN
typemap in the first method argument, and in fact, it also depends on the target language on implementing the 'disown' mechanism properly.
The use of
%newobject
is also integrated with reference counting and is covered in the C++ reference counted objects section.
Compatibility note: Previous versions of SWIG had a special
%new
directive. However, unlike
%newobject
, it only applied to the next declaration. For example:
訓示 SWIG 傳遞給該方法的第一個參數将被銷毀,是以,目智語言不應嘗試對其進行兩次配置設定。這類似于在第一個方法參數中使用
%delobject
類型映射,實際上,它還取決于目智語言是否正确實作了
DISOWN
機制。
disown
%newobject
的使用也與引用計數內建在一起,并在 C++ 引用計數對象章節中進行了介紹。
注意相容性:早期版本的 SWIG 具有特殊的
指令。但是,與
%new
不同,它僅适用于下一個聲明。例如:
%newobject
%new char *strdup(const char *s);
For now this is still supported but is deprecated.
How to shoot yourself in the foot: The
%newobject
directive is not a declaration modifier like the old
%new
directive. Don't write code like this:
目前,仍支援此功能,但已棄用。
如何射擊自己的腳:
指令與舊的
%newobject
指令不同,它不是一個聲明修飾符。不要寫這樣的代碼:
%new
%newobject
char *strdup(const char *s);
The results might not be what you expect.
結果可能不是你所期望的。
%feature
%feature
Both
%exception
%newobject
are examples of a more general purpose customization mechanism known as "features." A feature is simply a user-definable property that is attached to specific declarations. Features are attached using the
%feature
%exception
都是更通用的自定義機制(稱為“功能”)的示例。功能隻是附加到特定聲明的使用者可定義的屬性。功能使用
%newobject
指令附加。例如:
%feature
%feature("except") Object::allocate {
try {
$action
}
catch (MemoryError) {
croak("Out of memory");
}
}
%feature("new", "1") *::copy;
In fact, the
%exception
%newobject
directives are really nothing more than macros involving
%feature
:
實際上
%exception
就是包含
%newobject
的宏:
%feature
#define %exception %feature("except")
#define %newobject %feature("new", "1")
The name matching rules outlined in the Ambiguity resolution and renaming section applies to all
%feature
directives. In fact the
%rename
directive is just a special form of
%feature
. The matching rules mean that features are very flexible and can be applied with pinpoint accuracy to specific declarations if needed. Additionally, if no declaration name is given, a global feature is said to be defined. This feature is then attached to every declaration that follows. This is how global exception handlers are defined. For example:
消歧義析和重命名章節中概述的名稱比對規則适用于所有指令。實際上,
%feature
指令隻是
%rename
的一種特殊形式。比對規則意味着功能非常靈活,如果需要,可以精确地将其應用于特定聲明。此外,如果未給出聲明名稱,則稱已定義了全局功能。然後,此功能将附加到随後的每個聲明。這就是定義全局異常處理程式的方式。例如:
%feature
/* Define a global exception handler */
%feature("except") {
try {
$action
}
...
}
... bunch of declarations ...
%feature
directive can be used with different syntax. The following are all equivalent:
%feature
指令有不同的文法。以下都是等價的:
%feature("except") Object::method { $action };
%feature("except") Object::method %{ $action %};
%feature("except") Object::method " $action ";
%feature("except", "$action") Object::method;
The syntax in the first variation will generate the
{ }
delimiters used whereas the other variations will not.
第一個變體中的文法将生成使用的 { }
分隔符,而其他變體則不。
%feature
directive also accepts XML style attributes in the same way that typemaps do. Any number of attributes can be specified. The following is the generic syntax for features:
%feature
指令也以與類型映射相同的方式接受 XML 樣式的屬性。可以指定任意數量的屬性。以下是功能的通用文法:
%feature("name", "value", attribute1="AttributeValue1") symbol;
%feature("name", attribute1="AttributeValue1") symbol {value};
%feature("name", attribute1="AttributeValue1") symbol %{value%};
%feature("name", attribute1="AttributeValue1") symbol "value";
More than one attribute can be specified using a comma separated list. The Java module is an example that uses attributes in
%feature("except")
. The
throws
attribute specifies the name of a Java class to add to a proxy method's throws clause. In the following example,
MyExceptionClass
is the name of the Java class for adding to the throws clause.
可以使用逗号分隔的清單來指定多個屬性。Java 子產品是使用中的屬性的示例。
%feature("except")
屬性指定要添加到代理方法
throws
子句中 Java 類的名稱。在下面的示例中,
throw
是要添加到
MyExceptionClass
子句中的 Java 類的名稱。
throw
%feature("except", throws="MyExceptionClass") Object::method {
try {
$action
} catch (...) {
... code to throw a MyExceptionClass Java exception ...
}
};
Further details can be obtained from the Java exception handling section.
更多細節可以從 Java 異常處理章節獲得。
Feature flags are used to enable or disable a particular feature. Feature flags are a common but simple usage of
%feature
and the feature value should be either
1
to enable or
to disable the feature.
功能标志用于啟用或禁用特定功能。功能标志是常見但簡單的用法,值應為
%feature
則啟用,為 則禁用功能。
1
%feature("featurename") // enables feature
%feature("featurename", "1") // enables feature
%feature("featurename", "x") // enables feature
%feature("featurename", "0") // disables feature
%feature("featurename", "") // clears feature
Actually any value other than zero will enable the feature. Note that if the value is omitted completely, the default value becomes
1
, thereby enabling the feature. A feature is cleared by specifying no value, see Clearing features. The
%immutable
directive described in the Creating read-only variables section, is just a macro for
%feature("immutable")
, and can be used to demonstrates feature flags:
實際上,除 以外的任何值都将啟用該功能。請注意,如果該值被完全省略,則預設值為,進而啟用該功能。通過不指定任何值來清除功能,請參閱清除功能章節。在建立隻讀變量章節中描述的
1
%immutable
的宏,可以用來示範功能标記:
%feature("immutable")
// features are disabled by default
int red; // mutable
%feature("immutable"); // global enable
int orange; // immutable
%feature("immutable", "0"); // global disable
int yellow; // mutable
%feature("immutable", "1"); // another form of global enable
int green; // immutable
%feature("immutable", ""); // clears the global feature
int blue; // mutable
Note that features are disabled by default and must be explicitly enabled either globally or by specifying a targeted declaration. The above intersperses SWIG directives with C code. Of course you can target features explicitly, so the above could also be rewritten as:
請注意,預設情況下禁用功能,必須在全局範圍内或通過指定目标聲明來顯式啟用功能。上面的代碼将 SWIG 指令插入 C 代碼中。當然,你可以明确地定位功能,是以上面的内容也可以重寫為:
%feature("immutable", "1") orange;
%feature("immutable", "1") green;
int red; // mutable
int orange; // immutable
int yellow; // mutable
int green; // immutable
int blue; // mutable
The above approach allows for the C declarations to be separated from the SWIG directives for when the C declarations are parsed from a C header file. The logic above can of course be inverted and rewritten as:
當從 C 頭檔案解析 C 聲明時,上述方法允許将 C 聲明與 SWIG 指令分開。上面的邏輯當然可以颠倒并重寫為:
%feature("immutable", "1");
%feature("immutable", "0") red;
%feature("immutable", "0") yellow;
%feature("immutable", "0") blue;
int red; // mutable
int orange; // immutable
int yellow; // mutable
int green; // immutable
int blue; // mutable
As hinted above for
%immutable
, most feature flags can also be specified via alternative syntax. The alternative syntax is just a macro in the
swig.swg
Library file. The following shows the alternative syntax for the imaginary
featurename
feature:
就像上面對的提示一樣,大多數功能标志也可以通過其他文法來指定。替代文法隻是
%immutable
庫檔案中的宏。下面顯示了虛構的
swig.swg
功能的替代文法:
featurename
%featurename // equivalent to %feature("featurename", "1") ie enables feature
%nofeaturename // equivalent to %feature("featurename", "0") ie disables feature
%clearfeaturename // equivalent to %feature("featurename", "") ie clears feature
The concept of clearing features is discussed next.
接下來介紹清除功能的概念。
A feature stays in effect until it is explicitly cleared. A feature is cleared by supplying a
%feature
directive with no value. For example
%feature("name", "")
. A cleared feature means that any feature exactly matching any previously defined feature is no longer used in the name matching rules. So if a feature is cleared, it might mean that another name matching rule will apply. To clarify, let's consider the
except
feature again (
%exception
):
在明确将其清除之前,功能一直有效。通過提供無值的指令可以清除功能。例如
%feature
。清除的功能意味着名稱比對規則中不再使用與先前定義的功能完全比對的任何功能。是以,如果一項功能被清除,則可能意味着将應用另一個名稱比對規則。為了澄清,讓我們再次考慮
%feature("name", "")
功能(
except
):
%exception
// Define global exception handler
%feature("except") {
try {
$action
} catch (...) {
croak("Unknown C++ exception");
}
}
// Define exception handler for all clone methods to log the method calls
%feature("except") *::clone() {
try {
logger.info("$action");
$action
} catch (...) {
croak("Unknown C++ exception");
}
}
... initial set of class declarations with clone methods ...
// clear the previously defined feature
%feature("except", "") *::clone();
... final set of class declarations with clone methods ...
In the above scenario, the initial set of clone methods will log all method invocations from the target language. This specific feature is cleared for the final set of clone methods. However, these clone methods will still have an exception handler (without logging) as the next best feature match for them is the global exception handler.
Note that clearing a feature is not always the same as disabling it. Clearing the feature above with
%feature("except", "") *::clone()
is not the same as specifying
%feature("except", "0") *::clone()
. The former will disable the feature for clone methods - the feature is still a better match than the global feature. If on the other hand, no global exception handler had been defined at all, then clearing the feature would be the same as disabling it as no other feature would have matched.
Note that the feature must match exactly for it to be cleared by any previously defined feature. For example the following attempt to clear the initial feature will not work:
在上述情況下,初始的克隆方法将記錄來自目智語言的所有方法調用。最後一組克隆方法将清除此特定功能。但是,這些克隆方法仍将具有異常處理程式(不進行日志記錄),因為它們的下一個最佳功能比對是全局異常處理程式。
請注意,清除功能并不總是與禁用功能相同。用
清除上面的功能與指定
%feature("except", "0") *::clone()
%feature("except", "0") *::clone()
不同。前者将禁用克隆方法的功能,該功能仍然比全局功能更好。另一方面,如果根本沒有定義全局異常處理程式,則清除該功能與禁用該功能相同,因為沒有其他功能可以比對。
請注意,該功能必須完全比對才能被任何先前定義的功能清除。例如,以下清除初始功能的嘗試将無效:
%feature("except") clone() { logger.info("$action"); $action }
%feature("except", "") *::clone();
but this will:
但是這可以:
%feature("except") clone() { logger.info("$action"); $action }
%feature("except", "") clone();
SWIG provides macros for disabling and clearing features. Many of these can be found in the
swig.swg
library file. The typical pattern is to define three macros; one to define the feature itself, one to disable the feature and one to clear the feature. The three macros below show this for the "except" feature:
SWIG 提供了用于禁用和清除功能的宏。其中許多可以在庫檔案中找到。典型的模式是定義三個宏。一種是定義功能本身,一種是禁用功能,另一種是清除功能。下面的三個宏針對
swig.swg
功能顯示了這一點:
except
#define %exception %feature("except")
#define %noexception %feature("except", "0")
#define %clearexception %feature("except", "")
SWIG treats methods with default arguments as separate overloaded methods as detailed in the default arguments section. Any
%feature
targeting a method with default arguments will apply to all the extra overloaded methods that SWIG generates if the default arguments are specified in the feature. If the default arguments are not specified in the feature, then the feature will match that exact wrapper method only and not the extra overloaded methods that SWIG generates. For example:
SWIG 将具有預設參數的方法視為單獨的重載方法,如預設參數章節中所述。如果在功能中指定了預設參數,則以預設參數為目标的任何 %feature
都将應用于 SWIG 生成的所有額外重載方法。如果未在功能中指定預設參數,則功能将僅與該完全包裝方法比對,而不與 SWIG 生成的額外重載方法比對。例如:
%feature("except") hello(int i=0, double d=0.0) { ... }
void hello(int i=0, double d=0.0);
will apply the feature to all three wrapper methods, that is:
将把功能應用于所有三個包裝器方法,也就是:
void hello(int i, double d);
void hello(int i);
void hello();
If the default arguments are not specified in the feature:
如果功能中沒有指定預設參數:
%feature("except") hello(int i, double d) { ... }
void hello(int i=0, double d=0.0);
then the feature will only apply to this wrapper method:
那麼功能隻應用這個包裝器方法:
void hello(int i, double d);
and not these wrapper methods:
而不是這些方法:
void hello(int i);
void hello();
If
compactdefaultargs
are being used, then the difference between specifying or not specifying default arguments in a feature is not applicable as just one wrapper is generated.
Compatibility note: The different behaviour of features specified with or without default arguments was introduced in SWIG-1.3.23 when the approach to wrapping methods with default arguments was changed.
如果使用
compactdefaultargs
,則僅在生成一個包裝器時,在功能中指定或不指定預設參數之間的差別不适用。
注意相容性:當更改使用預設參數包裝方法的方法時,在 SWIG-1.3.23 中引入了使用或不使用預設參數指定的功能的不同行為。
As has been shown earlier, the intended use for the
%feature
directive is as a highly flexible customization mechanism that can be used to annotate declarations with additional information for use by specific target language modules. Another example is in the Python module. You might use
%feature
to rewrite proxy/shadow class code as follows:
如前所述,指令的預期用途是一種高度靈活的自定義機制,可用于為聲明加上附加資訊以供特定目智語言子產品使用。另一個示例在 Python 子產品中。你可以使用
%feature
來重寫代理/影子類代碼,如下所示:
%feature
%module example
%rename(bar_id) bar(int, double);
// Rewrite bar() to allow some nice overloading
%feature("shadow") Foo::bar(int) %{
def bar(*args):
if len(args) == 3:
return apply(examplec.Foo_bar_id, args)
return apply(examplec.Foo_bar, args)
%}
class Foo {
public:
int bar(int x);
int bar(int x, double y);
}
Further details of
%feature
usage is described in the documentation for specific language modules.
%feature
用法的更多詳細資訊在特定語言子產品的文檔中進行了描述。
★ 持續學習 ★ 堅持創作 ★