SWIG 3 中文手冊——7. SWIG 和 C++11

7 SWIG 與 C++11

7.1 引言

This chapter gives you a brief overview about the SWIG implementation of the C++11 standard. This part of SWIG is still a work in progress.java

SWIG supports the new C++ syntax changes with some minor limitations in some areas such as decltype expressions and variadic templates. Wrappers for the new STL types (unordered_ containers, result_of, tuples) are incomplete. The wrappers for the new containers would work much like the C++03 containers and users are welcome to help by adapting the existing container interface files and submitting them as a patch for inclusion in future versions of SWIG.python

本章爲你簡要概述了 C++11 標準的SWIG實現。SWIG 的這一部分仍在開發中。正則表達式

SWIG 支持新的 C++ 語法改動,但在諸如 decltype 表達式和可變參數模板等某些方面存在一些小的限制。STL 新類型(unordered_容器、result_of、元組)的包裝不完整。新容器的包裝器將像 C++03 容器同樣工做,歡迎用戶適配現有容器接口文件並將其做爲補丁提交以供未來的 SWIG 版本使用。算法

7.2 核心語言變動

7.2.1 右值引用與轉移語義

SWIG correctly parses the rvalue reference syntax &&, for example the typical usage of it in the move constructor and move assignment operator below:express

SWIG 正確地解析了右值引用語法 &&,例如,下面轉移構造函數和轉移賦值運算符的典型用法:編程

class MyClass {
...
  std::vector<int> numbers;
public:
  MyClass(MyClass &&other) : numbers(std::move(other.numbers)) {}
  MyClass & operator=(MyClass &&other) {
    numbers = std::move(other.numbers);
    return *this;
  }
};

Rvalue references are designed for C++ temporaries and so are not very useful when used from non-C++ target languages. Generally you would just ignore them via %ignore before parsing the class. For example, ignore the move constructor:閉包

右值引用是爲 C++ 臨時對象設計的,所以從非 C++ 目標語言中使用時,它不是頗有用。一般,你只須要在解析類以前經過 %ignore 忽略它們便可。例如,忽略轉移構造函數:app

%ignore MyClass::MyClass(MyClass &&);

The plan is to ignore move constructors by default in a future version of SWIG. Note that both normal assignment operators as well as move assignment operators are ignored by default in most target languages with the following warning:less

計劃在 SWIG 的將來版本中默認忽略轉移構造函數。請注意,在大多數目標語言中,默認狀況下普通賦值運算符和移動賦值運算符都會被忽略,並顯示如下警告:

example.i:18: Warning 503: Can't wrap `operator =` unless renamed to a valid identifier.

7.2.2 通用常量表達式

SWIG parses and identifies the keyword constexpr, but cannot fully utilise it. These C++ compile time constants are usable as runtime constants from the target languages. Below shows example usage for assigning a C++ compile time constant from a compile time constant function:

SWIG 解析並識別關鍵字 constexpr,但沒法充分利用它。這些 C++ 編譯時常量可用做目標語言的運行時常量。下面顯示了從編譯時常量函數分配 C++ 編譯時常量的示例用法:

constexpr int XXX() { return 10; }
constexpr int YYY = XXX() + 100;

When either of these is used from a target language, a runtime call is made to obtain the underlying constant.

當從目標語言中使用這兩種方法中的任何一種時,都會進行運行時調用以獲取基礎常量。

7.2.3 外部模板

SWIG correctly parses the keywords extern template. However, this template instantiation suppression in a translation unit has no relevance outside of the C++ compiler and so is not used by SWIG. SWIG only uses %template for instantiating and wrapping templates.

SWIG 正確地解析了關鍵字 extern template。可是,轉換單元中的模板實例化抑制在 C++ 編譯器以外沒有任何關聯,所以 SWIG 不會使用它。SWIG 僅使用 %template 實例化和包裝模板。

template class std::vector<int>;        // C++03 explicit instantiation in C++
extern template class std::vector<int>; // C++11 explicit instantiation suppression in C++
%template(VectorInt) std::vector<int>;  //SWIGinstantiation

7.2.4 初始化列表

Initializer lists are very much a C++ compiler construct and are not very accessible from wrappers as they are intended for compile time initialization of classes using the special std::initializer_list type. SWIG detects usage of initializer lists and will emit a special informative warning each time one is used:

初始化列表是 C++ 編譯器的一種構造,而且對於包裝器來講不是很容易訪問,由於它們打算使用特殊的 std::initializer_list 類型進行類的編譯時初始化。SWIG 會檢測到初始化列表的使用,而且每次使用初始化列表時都會發出特殊的提示性警告:

example.i:33: Warning 476: Initialization using std::initializer_list.

Initializer lists usually appear in constructors but can appear in any function or method. They often appear in constructors which are overloaded with alternative approaches to initializing a class, such as the std container's push_back method for adding elements to a container. The recommended approach then is to simply ignore the initializer-list constructor, for example:

初始化列表一般出如今構造函數中,但也能夠出如今任何函數或方法中。它們常常出如今構造函數中,這些構造函數被初始化類的替代方法重載,例如 std 容器用於添加元素的 push_back 方法。推薦的方法是簡單地忽略初始化列表構造函數,例如:

%ignore Container::Container(std::initializer_list<int>);
class Container {
public:
  Container(std::initializer_list<int>); // initializer-list constructor
  Container();
  void push_back(const int &);
  ...
};

Alternatively you could modify the class and add another constructor for initialization by some other means, for example by a std::vector:

或者,你能夠修改該類並經過其餘方法(例如,經過 std::vector)添加另外一個用於初始化的構造函數:

%include <std_vector.i>
class Container {
public:
  Container(const std::vector<int> &);
  Container(std::initializer_list<int>); // initializer-list constructor
  Container();
  void push_back(const int &);
  ...
};

And then call this constructor from your target language, for example, in Python, the following will call the constructor taking the std::vector:

而後從你的目標語言調用此構造函數,例如在 Python 中,如下將使用 std::vector 調用該構造函數:

>>> c = Container([1, 2, 3, 4])

If you are unable to modify the class being wrapped, consider ignoring the initializer-list constructor and using %extend to add in an alternative constructor:

若是你沒法修改被包裝的類,請考慮忽略初始化列表構造函數,並使用 %extend 添加備用構造函數:

%include <std_vector.i>
%extend Container {
  Container(const std::vector<int> &elements) {
    Container *c = new Container();
    for (int element : elements)
      c->push_back(element);
    return c;
  }
}

%ignore Container::Container(std::initializer_list<int>);

class Container {
public:
  Container(std::initializer_list<int>); // initializer-list constructor
  Container();
  void push_back(const int &);
  ...
};

The above makes the wrappers look is as if the class had been declared as follows:

這使得包裝器看起來好像類是以下聲明的:

%include <std_vector.i>
class Container {
public:
  Container(const std::vector<int> &);
//  Container(std::initializer_list<int>); // initializer-list constructor (ignored)
  Container();
  void push_back(const int &);
  ...
};

std::initializer_list is simply a container that can only be initialized at compile time. As it is just a C++ type, it is possible to write typemaps for a target language container to map ontostd::initializer_list. However, this can only be done for a fixed number of elements as initializer lists are not designed to be constructed with a variable number of arguments at runtime. The example below is a very simple approach which ignores any parameters passed in and merely initializes with a fixed list of fixed integer values chosen at compile time:

std::initializer_list 只是一個只能在編譯時初始化的容器。因爲它只是一種 C++ 類型,所以能夠爲目標語言容器編寫類型映射以映射到 std::initializer_list 上。可是,只能對固定數量的元素執行此操做,由於初始化列表並不是設計爲在運行時使用可變數量的參數構造。下面的示例是一個很是簡單的方法,它忽略傳入的任何參數,僅使用在編譯時選擇的固定整數值的固定列表進行初始化:

%typemap(in) std::initializer_list<int> {
  $1 = {10, 20, 30, 40, 50};
}
class Container {
public:
  Container(std::initializer_list<int>); // initializer-list constructor
  Container();
  void push_back(const int &);
  ...
};

Any attempt at passing in values from the target language will be ignored and be replaced by {10, 20, 30, 40, 50}. Needless to say, this approach is very limited, but could be improved upon, but only slightly. A typemap could be written to map a fixed number of elements on to the std::initializer_list, but with values decided at runtime. The typemaps would be target language specific.

Note that the default typemap for std::initializer_list does nothing but issue the warning and hence any user supplied typemaps will override it and suppress the warning.

從目標語言傳遞值的任未嘗試都將被忽略,並由 {10, 20, 30, 40, 50} 代替。不用說,這種方法是很是侷限的,可是能夠改進,不過只能稍微改進。能夠編寫一個類型映射來將固定數量的元素映射到 std::initializer_list 上,可是要在運行時肯定其值。類型映射將是特定於目標語言的。

請注意,std::initializer_list 的默認類型映射只會發出警告,而不會執行任何操做,所以任何用戶提供的類型映射都將覆蓋它並禁止顯示警告。

7.2.5 統一初始化

The curly brackets {} for member initialization are fully supported by SWIG:

SWIG 徹底支持用 {} 來實現成員初始化。

struct BasicStruct {
 int x;
 double y;
};

struct AltStruct {
  AltStruct(int x, double y) : x_{x}, y_{y} {}

  int x_;
  double y_;
};

BasicStruct var1{5, 3.2}; // only fills the struct components
AltStruct var2{2, 4.3};   // calls the constructor

Uniform initialization does not affect usage from the target language, for example in Python:

統一初始化對目標語言的使用不起做用,例如在 Python 中:

>>> a = AltStruct(10, 142.15)
>>> a.x_
10
>>> a.y_
142.15

7.2.6 類型推斷

SWIG supports decltype() with some limitations. Single variables are allowed, however, expressions are not supported yet. For example, the following code will work:

SWIG 對 decltype() 的支持有一些限制。容許使用單個變量,可是尚不支持表達式。例如,如下代碼將起做用:

int i;
decltype(i) j;

However, using an expression inside the decltype results in syntax error:

可是,在 decltype 中使用表達式將產生語法錯誤:

int i; int j;
decltype(i+j) k;  // syntax error

7.2.7 基於範圍的 for 循環

This feature is part of the implementation block only. SWIG ignores it.

這一功能只是實現障礙的一部分。SWIG 忽略了它。

7.2.8 Lambda 函數和表達式

SWIG correctly parses most of the Lambda functions syntax. For example:

SWIG 能正確解析絕大部分 Lambda 函數語法。例如:

auto val = [] { return something; };
auto sum = [](int x, int y) { return x+y; };
auto sum = [](int x, int y) -> int { return x+y; };

The lambda functions are removed from the wrappers for now, because of the lack of support for closures (scope of the lambda functions) in the target languages.

Lambda functions used to create variables can also be parsed, but due to limited support of auto when the type is deduced from the expression, the variables are simply ignored.

因爲缺乏對目標語言中閉包(lambda 函數範圍)的支持,所以暫時將 lambda 函數從包裝器中刪除了。

也能夠解析用於建立變量的 Lambda 函數,可是因爲從表達式推導出類型時對 auto 的支持有限,所以變量將被忽略。

auto six = [](int x, int y) { return x+y; }(4, 2);

Better support should be available in a later release.

後續版本將會提供更好的支持。

7.2.9 替代函數語法(Alternate function syntax)

SWIG fully supports the new definition of functions. For example:

SWIG 徹底支持這種新的函數定義。例如:

struct SomeStruct {
  int FuncName(int x, int y);
};

can now be written as in C++11:

在 C++11 中能夠寫成:

struct SomeStruct {
  auto FuncName(int x, int y) -> int;
};

auto SomeStruct::FuncName(int x, int y) -> int {
  return x + y;
}

The usage in the target languages remains the same, for example in Python:

在目標語言中的用法是相同的,例如在 Python 中:

>>> a = SomeStruct()
>>> a.FuncName(10, 5)
15

SWIG will also deal with type inference for the return type, as per the limitations described earlier. For example:

根據前面所述的限制,SWIG 還將進行返回類型的類型推斷。例如:

auto square(float a, float b) -> decltype(a);

7.2.10 對象構造改進

There are three parts to object construction improvement. The first improvement is constructor delegation such as the following:

對象構造改進分爲三個部分。第一部分改進是構造函數委託,例如:

class A {
public:
  int a;
  int b;
  int c;

  A() : A(10) {}
  A(int aa) : A(aa, 20) {}
  A(int aa, int bb) : A(aa, bb, 30) {}
  A(int aa, int bb, int cc) { a=aa; b=bb; c=cc; }
};

where peer constructors can be called. SWIG handles this without any issue.

The second improvement is constructor inheritance via a using declaration. This is parsed correctly, but the additional constructors are not currently added to the derived proxy class in the target language. An example is shown below:

能夠調用對等構造函數的地方。SWIG 能夠毫無問題地進行處理。

第二部分改進是經過使用 using 聲明的構造函數繼承。能夠正確地對此進行分析,可是當前未將其餘構造函數添加到目標語言中的派生代理類。一個例子以下所示:

class BaseClass {
public:
  BaseClass(int iValue);
};

class DerivedClass: public BaseClass {
  public:
  using BaseClass::BaseClass; // Adds DerivedClass(int) constructor
};

The final part is member initialization at the site of the declaration. This kind of initialization is handled by SWIG.

最後一部分是聲明位置的成員初始化。這種初始化由 SWIG 處理。

class SomeClass {
public:
  SomeClass() {}
  explicit SomeClass(int new_value) : value(new_value) {}

  int value = 5;
};

7.2.11 顯式 overridesfinal

The special identifiers final and override can be used on methods and destructors, such as in the following example:

特殊標識符 finaloverride 可用於方法和析構函數,例如如下示例:

struct BaseStruct {
  virtual void ab() const = 0;
  virtual void cd();
  virtual void ef();
  virtual ~BaseStruct();
};

struct DerivedStruct : BaseStruct {
  virtual void ab() const override;
  virtual void cd() final;
  virtual void ef() final override;
  virtual ~DerivedStruct() override;
};

7.2.12 空指針常量

The nullptr constant is mostly unimportant in wrappers. In the few places it has an effect, it is treated like NULL.

在包裝器中,nullptr 常量幾乎不重要。少數有它會起做用的地方,它被視爲 NULL

7.2.13 強類型枚舉

SWIG supports strongly typed enumerations and parses the new enum class syntax and forward declarator for the enums, such as:

SWIG 支持強類型枚舉,併爲枚舉解析新的 enum class 語法和前向聲明符,例如:

enum class MyEnum : unsigned int;

Strongly typed enums are often used to avoid name clashes such as the following:

強類型枚舉一般用來避免名稱衝突,例以下面:

struct Color {
  enum class RainbowColors : unsigned int {
    Red, Orange, Yellow, Green, Blue, Indigo, Violet
  };

  enum class WarmColors {
    Yellow, Orange, Red
  };

  // Note normal enum
  enum PrimeColors {
    Red=100, Green, Blue
  };
};

There are various ways that the target languages handle enums, so it is not possible to precisely state how they are handled in this section. However, generally, most scripting languages mangle in the strongly typed enumeration's class name, but do not use any additional mangling for normal enumerations. For example, in Python, the following code

目標語言使用多種方式處理枚舉,所以在本節中沒法精確說明它們的處理方式。可是,一般,大多數腳本語言都以強類型枚舉的類名進行修飾,但對於普通枚舉不使用任何其餘修飾。例如,在 Python 中,如下代碼

print Color.RainbowColors_Red, Color.WarmColors_Red, Color.Red

results in

的結果是

0 2 100

The strongly typed languages often wrap normal enums into an enum class and so treat normal enums and strongly typed enums the same. The equivalent in Java is:

強類型語言一般將普通枚舉包裝到枚舉類中,所以普通枚舉和強類型枚舉處理方式相同。Java 中的等效項是:

System.out.println(
    Color.RainbowColors.Red.SWIGValue() + " " +
    Color.WarmColors.Red.SWIGValue() + " " +
    Color.PrimeColors.Red.SWIGValue());

7.2.14 雙尖括號(>>

SWIG correctly parses the symbols >> as closing the template block, if found inside it at the top level, or as the right shift operator >> otherwise.

SWIG 正確地將符號 >> 解析爲模板塊的封閉(若是在頂層的塊中發現),或者正確的解析爲右移運算符 >>

std::vector<std::vector<int>> myIntTable;

7.2.15 顯式轉換運算符

SWIG correctly parses the keyword explicit for operators in addition to constructors now. For example:

如今,SWIG 除了爲構造函數以外,還爲運算符正確解析了關鍵字 explicit。例如:

class U {
public:
  int u;
};

class V {
public:
  int v;
};

class TestClass {
public:
  //implicit converting constructor
  TestClass(U const &val) { t=val.u; }

  // explicit constructor
  explicit TestClass(V const &val) { t=val.v; }

  int t;
};

struct Testable {
  // explicit conversion operator
  explicit operator bool() const {
    return false;
  }
};

The effect of explicit constructors and operators has little relevance for the proxy classes as target languages don't have the same concepts of implicit conversions as C++. Conversion operators either with or without explicit need renaming to a valid identifier name in order to make them available as a normal proxy method.

顯式構造函數和運算符對代理類的影響不大,由於目標語言沒有與 C++ 相同的隱式轉換概念。帶有或不帶有 explicit 的轉換運算符都須要重命名爲有效的標識符名稱,以使其能夠用做常規代理方法。

7.2.16 類型別名與別名模板

A type alias is a statement of the form:

類型別名是這種形式的語句:

using PFD = void (*)(double); // New introduced syntax

which is equivalent to the old style typedef:

這等價於舊式的 typedef

typedef void (*PFD)(double);  // The old style

The following is an example of an alias template:

下面的例子是一個別名模板:

template< typename T1, typename T2, int N >
class SomeType {
public:
  T1 a;
  T2 b;
};

template< typename T2 >
using TypedefName = SomeType<char*, T2, 5>;

SWIG supports both type aliasing and alias templates. However, in order to use an alias template, two %template directives must be used:

SWIG 支持類型別名和別名模板。可是,爲了使用別名模板,必須使用兩個 %template 指令:

%template(SomeTypeBool) SomeType<char*, bool, 5>;
%template() TypedefName<bool>;

Firstly, the actual template is instantiated with a name to be used by the target language, as per any template being wrapped. Secondly, the empty template instantiation, %template(), is required for the alias template. This second requirement is necessary to add the appropriate instantiated template type into the type system as SWIG does not automatically instantiate templates. See the Templates section for more general information on wrapping templates.

首先,實際模板被實例化,並賦予一個名字供目標語言使用,與任何對模板的包裝同樣。其次,別名模板須要空模板實例化 %template()。第二個要求是將適當的實例化模板類型添加到類型系統中,這是必需的,由於 SWIG 不會自動實例化模板。有關包裝模板的更多常規信息,請參見模板部分。

7.2.17 無限制共用體

SWIGfully supports any type inside a union even if it does not define a trivial constructor. For example, the wrapper for the following code correctly provides access to all members in the union:

SWIG 徹底支持共用體內的任何類型,即便它沒有定義瑣碎的構造函數。例如,如下代碼的包裝程序正確地提供了對共用體中全部成員的訪問:

struct point {
  point() {}
  point(int x, int y) : x_(x), y_(y) {}
  int x_, y_;
};

#include <new> // For placement `new` in the constructor below
union P {
  int z;
  double w;
  point p; // Illegal in C++03; legal in C++11.
  // Due to the point member, a constructor definition is required.
  P() {
    new(&p) point();
  }
} p1;

7.2.18 可變參數模板

SWIG supports the variadic templates syntax (inside the <> block, variadic class inheritance and variadic constructor and initializers) with some limitations. The following code is correctly parsed:

SWIG 有限的支持可變參數模板語法(在 <> 塊中的可變參數類繼承,以及可變參數構造函數和初始化)。如下代碼的正確解析:

template <typename... BaseClasses> class ClassName : public BaseClasses... {
public:
  ClassName (BaseClasses &&... baseClasses) : BaseClasses(baseClasses)... {}
}

For now however, the %template directive only accepts one parameter substitution for the variable template parameters.

可是如今,%template 指令只接受一個參數替換可變模板參數。

%template(MyVariant1) ClassName<>         // zero argument not supported yet
%template(MyVariant2) ClassName<int>      // ok
%template(MyVariant3) ClassName<int, int> // too many arguments not supported yet

Support for the variadic sizeof() function is correctly parsed:

對可變參數函數 sizeof() 的支持被正確解析爲:

const int SIZE = sizeof...(ClassName<int, int>);

In the above example SIZE is of course wrapped as a constant.

在上面的例子中 SIZE 被包裝爲一個常量。

7.2.19 新的字符串文字

SWIG supports wide string and Unicode string constants and raw string literals.

SWIG 支持寬字符串和 Unicode 字符串常量以及原始字符串文字。

// New string literals
wstring         aa =  L"Wide string";
const char     *bb = u8"UTF-8 string";
const char16_t *cc =  u"UTF-16 string";
const char32_t *dd =  U"UTF-32 string";

// Raw string literals
const char      *xx =        ")I`m an \"ascii\" \\ string.";
const char      *ee =   R"XXX()I`m an "ascii" \ string.)XXX"; // same as xx
wstring          ff =  LR"XXX(I`m a "raw wide" \ string.)XXX";
const char      *gg = u8R"XXX(I`m a "raw UTF-8" \ string.)XXX";
const char16_t  *hh =  uR"XXX(I`m a "raw UTF-16" \ string.)XXX";
const char32_t  *ii =  UR"XXX(I`m a "raw UTF-32" \ string.)XXX";

Non-ASCII string support varies quite a bit among the various target languages though.

Note: There is a bug currently where SWIG's preprocessor incorrectly parses an odd number of double quotes inside raw string literals.

可是,非 ASCII 字符串支持在各類目標語言中相差很大。

注意:當前存在一個錯誤,其中 SWIG 的預處理程序錯誤地解析了原始字符串文字中的奇數雙引號。

7.2.20 用戶定義文字

SWIG parses the declaration of user-defined literals, that is, the operator "" _mysuffix() function syntax.

Some examples are the raw literal:

SWIG 能夠解析用戶定義的文字的聲明,即 operator "" _mysuffix() 的語法。

一些示例是原始文字:

OutputType operator "" _myRawLiteral(const char * value);

numeric cooked literals:

數值型文字:

OutputType operator "" _mySuffixIntegral(unsigned long long);
OutputType operator "" _mySuffixFloat(long double);

and cooked string literals:

字符串型文字:

OutputType operator "" _mySuffix(const char * string_values, size_t num_chars);
OutputType operator "" _mySuffix(const wchar_t * string_values, size_t num_chars);
OutputType operator "" _mySuffix(const char16_t * string_values, size_t num_chars);
OutputType operator "" _mySuffix(const char32_t * string_values, size_t num_chars);

Like other operators that SWIG parses, a warning is given about renaming the operator in order for it to be wrapped:

像 SWIG 解析的其餘運算符同樣,給出了有關重命名該運算符的警告,以便對其進行包裝:

example.i:27: Warning 503: Can't wrap `operator "" _myRawLiteral` unless renamed to a valid identifier.

If %rename is used, then it can be called like any other wrapped method. Currently you need to specify the full declaration including parameters for %rename:

若是使用 %rename,則能夠像其餘任何包裝方法同樣調用它。當前,你須要指定完整的聲明,包括 %rename 的參數:

%rename(MyRawLiteral)  operator"" _myRawLiteral(const char * value);

Or if you just wish to ignore it altogether:

或者,你能夠直接忽略掉:

%ignore operator "" _myRawLiteral(const char * value);

Note that use of user-defined literals such as the following still give a syntax error:

請注意,使用用戶定義文字(如如下內容)仍會產生語法錯誤:

OutputType var1 = "1234"_suffix;
OutputType var2 = 1234_suffix;
OutputType var3 = 3.1416_suffix;

7.2.21 thread_local 存儲

SWIG correctly parses the thread_local keyword. For example, variables reachable by the current thread can be defined as:

SWIG 能正確解析 thread_local 關鍵字。例如,當前線程可訪問的變量能夠定義爲:

struct A {
  static thread_local int val;
};
thread_local int global_val;

The use of the thread_local storage specifier does not affect the wrapping process; it does not modify the wrapper code compared to when it is not specified. A variable will be thread local if accessed from different threads from the target language in the same way that it will be thread local if accessed from C++ code.

使用 thread_local 存儲說明符不會影響包裝過程。與未指定時相比,它不會修改包裝器代碼。若是從目標語言的不一樣線程訪問變量,則該變量將是線程局部的,就像從 C++ 代碼訪問該變量時同樣。

7.2.22 顯式默認函數(defaulted function)與刪除函數(deleted function)

SWIG handles explicitly defaulted functions, that is, = default added to a function declaration. Deleted definitions, which are also called deleted functions, have = delete added to the function declaration. For example:

SWIG 處理顯式默認函數,即添加到函數聲明中的 = default。刪除的定義(也稱爲刪除函數)是在函數聲明中添加 = delete。例如:

struct NonCopyable {
  NonCopyable & operator=(const NonCopyable &) = delete; /* Removes operator= */
  NonCopyable(const NonCopyable &) = delete;             /* Removes copy constructor */
  NonCopyable() = default;                               /* Explicitly allows the empty constructor */
};

Wrappers for deleted functions will not be available in the target language. Wrappers for defaulted functions will of course be available in the target language. Explicitly defaulted functions have no direct effect for SWIG wrapping as the declaration is handled much like any other method declaration parsed by SWIG.

Deleted functions are also designed to prevent implicit conversions when calling the function. For example, the C++ compiler will not compile any code which attempts to use an int as the type of the parameter passed to f below:

目標語言將沒法使用刪除函數的包裝器。固然,目標語言可以使用默認函數的包裝器。顯式默認函數對 SWIG 包裝沒有直接影響,由於聲明的處理方式與 SWIG 解析的任何其餘方法聲明很是類似。

刪除函數還旨在防止在調用函數時進行隱式轉換。例如,C++ 編譯器不會編譯任何試圖將 int 傳遞給下面 f 的代碼:

struct NoInt {
  void f(double i);
  void f(int) = delete;
};

This is a C++ compile time check and SWIG does not make any attempt to detect if the target language is using an int instead of a double though, so in this case it is entirely possible to pass an int instead of a double to f from Java, Python etc.

這是 C++ 編譯時檢查,可是 SWIG 不會嘗試檢測目標語言是否使用 int 而不是 double,所以在這種狀況下,徹底有可能從 Java,Python 等將 int 而不是 double 傳遞給 f

7.2.23 long long int 類型

SWIG correctly parses and uses the new long long type already introduced in C99 some time ago.

SWIG 正確地解析並使用了早先 C99 中已經引入的 long long 類型。

7.2.24 靜態斷言

SWIG correctly parses the new static_assert declarations. This is a C++ compile time directive so there isn't anything useful that SWIG can do with it.

SWIG 正確地解析了新的 static_assert 聲明。這是一個 C++ 編譯時指令,所以 SWIG 不能對其執行任何有用的操做。

template <typename T>
struct Check {
  static_assert(sizeof(int) <= sizeof(T), "not big enough");
};

7.2.25 容許在沒有顯式對象的狀況下對類成員使用 sizeof

SWIG can parse the new sizeof() on types as well as on objects. For example:

SWIG 能夠在類型和對象上解析新的 sizeof() 函數。例如:

struct A {
  int member;
};

const int SIZE = sizeof(A::member); // does not work with C++03. Okay with C++11

In Python:

在 Python 中:

>>> SIZE
8

7.2.26 異常規範與 noexcept

C++11 added in the noexcept specification to exception specifications to indicate that a function simply may or may not throw an exception, without actually naming any exception. SWIG understands these, although there isn't any useful way that this information can be taken advantage of by target languages, so it is as good as ignored during the wrapping process. Below are some examples of noexcept in function declarations:

C++11 在 noexcept 規範中添加了異常規範,以指示一個函數可能會也可能不會拋出異常,而無需實際命名任何異常。儘管沒有任何有用的方法可使目標語言利用此信息,但 SWIG 能理解這些知識,所以在包裝過程當中它就像被忽略了同樣。如下是函數聲明中的 noexcept 的一些示例:

static void noex1() noexcept;
int noex2(int) noexcept(true);
int noex3(int, bool) noexcept(false);

7.2.27 控制與查詢對象對齊

An alignof operator is used mostly within C++ to return alignment in number of bytes, but could be used to initialize a variable as shown below. The variable's value will be available for access by the target language as any other variable's compile time initialised value.

alignof 運算符一般在 C++ 中使用,以字節爲單位返回對齊方式,但可用於初始化變量,以下所示。該變量的值與其餘任何變量在編譯時的初始化值同樣可供目標語言訪問。

const int align1 = alignof(A::member);

The alignas specifier for variable alignment is not yet supported. Example usage:

尚不支持用於變量對齊的 alignas 說明符。示例:

struct alignas(16) S {
  int num;
};
alignas(double) unsigned char c[sizeof(double)];

Use the preprocessor to work around this for now:

如今使用預處理器解決此問題:

#define alignas(T)

7.2.28 屬性

Attributes such as those shown below, are not yet supported and will give a syntax error.

尚不支持以下所示的屬性,這些屬性會產生語法錯誤。

int [[attr1]] i [[attr2, attr3]];

[[noreturn, nothrow]] void f [[noreturn]] ();

7.3 標準庫變動

7.3.1 線程工具

SWIG does not currently wrap or use any of the new threading classes introduced (thread, mutex, locks, condition variables, task). The main reason is that SWIGtarget languages offer their own threading facilities so there is limited use for them.

SWIG 當前不包裝或使用任何新引入的線程類(線程、互斥鎖、鎖、條件變量、任務)。主要緣由是 SWIG 的目標語言提供了本身的線程工具,所以使用範圍有限。

7.3.2 元組類型

SWIG does not provide library files for the new tuple types yet. Variadic template support requires further work to provide substantial tuple wrappers.

SWIG 還沒有提供新的元組類型的庫文件。可變參數模板支持須要進一步的工做以提供大量的元組包裝器。

7.3.3 哈希表

The new hash tables in the STL are unordered_set, unordered_multiset, unordered_map, unordered_multimap. These are not available inSWIG , but in principle should be easily implemented by adapting the current STL containers.

STL 中新的哈希表是 unordered_setunordered_multisetunordered_mapunordered_multimap。這些在 SWIG 中不可用,但原則上應經過適應當前的 STL 容器輕鬆實現。

7.3.4 正則表達式

While SWIG could provide wrappers for the new C++11 regular expressions classes, there is little need as the target languages have their own regular expression facilities.

儘管 SWIG 能夠爲新的 C++11 正則表達式類提供包裝器,可是幾乎沒有必要,由於目標語言具備本身的正則表達式工具。

7.3.5 通用智能指針

SWIG provides special smart pointer handling for std::shared_ptr in the same way it has support for boost::shared_ptr. Please see the shared_ptr smart pointerlibrary section. There is no special smart pointer handling available for std::weak_ptr and std::unique_ptr yet.

SWIG 以支持 boost::shared_ptr 的相同方式爲 std::shared_ptr 提供了特殊的智能指針處理。請參閱 shared_ptr 智能指針庫部分。std::weak_ptrstd::unique_ptr 智能指針尚無特殊處理。

7.3.6 擴展的隨機數工具

This feature extends and standardizes the standard library only and does not effect the C++ language nor SWIG.

此功能僅擴展和標準化了標準庫,而且不影響 C++ 與 SWIG 。

7.3.7 包裝器引用

Wrapper references are similar to normal C++ references but are copy-constructible and copy-assignable. They could conceivably be used in public APIs. There is no special support for std::reference_wrapper inSWIGthough. Users would need to write their own typemaps if wrapper references are being used and these would be similar to the plain C++ reference typemaps.

包裝器引用與普通 C++ 引用類似,但它們可複製構造和可複製分配。能夠想象它們能夠在公共 API 中使用。可是,SWIG 中沒有對 std::reference_wrapper 的特殊支持。若是使用包裝器引用,則用戶將須要編寫本身的類型映射,而且它們將與普通的 C++ 引用類型映射類似。

7.3.8 函數對象的多態包裝器

SWIG supports functor classes in a few languages in a very natural way. However nothing is provided yet for the new std::function template. SWIG will parse usage of the template like any other template.

SWIG 很是天然地支持幾種語言的仿函數類。可是,尚未爲新的 std::function 模板提供任何東西。SWIG 將像解析其餘模板同樣解析該模板的用法。

%rename(__call__) Test::operator(); // Default renaming used for Python

struct Test {
  bool operator()(int x, int y); // function object
};

#include <functional>
std::function<void (int, int)> pF = Test;   // function template wrapper

Example of supported usage of the plain functor from Python is shown below. It does not involve std::function.

下面示例顯示了所支持的 Python 仿函數用法。它不涉及 std::function

t = Test()
b = t(1, 2) # invoke C++ function object

7.3.9 元編程的 type_traits

The type_traits functions to support C++ metaprogramming is useful at compile time and is aimed specifically at C++ development:

支持 C++ 元編程的 type_traits 函數在編譯時頗有用,而且專門針對 C++ 開發:

#include <type_traits>

// First way of operating.
template< bool B > struct algorithm {
  template< class T1, class T2 > static int do_it(T1 &, T2 &)  { /*...*/ return 1; }
};

// Second way of operating.
template<> struct algorithm<true> {
  template< class T1, class T2 > static int do_it(T1, T2)  { /*...*/ return 2; }
};

// Instantiating `elaborate` will automatically instantiate the
// correct way to operate, depending on the types used.
template< class T1, class T2 > int elaborate(T1 A, T2 B) {
  // Use the second way only if `T1` is an integer and if `T2` is a floating point,
  // otherwise use the first way.
  return algorithm< std::is_integral<T1>::value && std::is_floating_point<T2>::value >::do_it(A, B);
}

SWIG correctly parses the template specialization, template types etc. However, metaprogramming and the additional support in the type_traits header is really for compile time and is not much use at runtime for the target languages. For example, as SWIG requires explicit instantiation of templates via %template, there isn't much that std::is_integral<int> is going to provide by itself. However, template functions using such metaprogramming techniques might be useful to wrap. For example, the following instantiations could be made:

SWIG 正確地解析了模板特化、模板類型等。可是,元編程和 type_traits 頭文件中的其餘支持其實是在編譯時使用的,在運行時對於目標語言而言使用並很少。例如,因爲 SWIG 須要經過 %template 來顯式實例化模板,所以 std::is_integral<int> 自己不會提供太多功能。可是,使用此類元編程技術的模板功能可能對包裝有用。例如,能夠進行如下實例化:

%template(Elaborate) elaborate<int, int>;
%template(Elaborate) elaborate<int, double>;

Then the appropriate algorithm can be called for the subset of types given by the above %template instantiations from a target language, such as Python:

而後,能夠針對目標語言(例如 Python)中上述 %template 實例化所給出的類型子集調用適當的算法:

>>> Elaborate(0, 0)
1
>>> Elaborate(0, 0.0)
2

7.3.10 計算函數對象返回類型的統一方法

The new std::result_of class introduced in the <functional> header provides a generic way to obtain the return type of a function type via std::result_of::type. There isn't any library interface file to support this type. With a bit of work, SWIG will deduce the return type of functions when used in std::result_of using the approach shown below. The technique basically forward declares the std::result_of template class, then partially specializes it for the function types of interest. SWIG will use the partial specialization and hence correctly use the std::result_of::type provided in the partial specialization.

<functional> 頭文件中引入的 std::result_of 類提供了一種經過 std::result_of::type 獲取函數類型的返回類型的通用方法。沒有任何庫接口文件支持此類型。通過一點工做,SWIG 將使用如下所示的方法推導使用 std::result_of 時函數的返回類型。該技術基本上向前聲明瞭 std::result_of 模板類,而後將其偏特化用於感興趣的函數類型。SWIG 將使用偏特化,所以正確使用了偏特化中提供的 std::result_of::type

%inline %{
#include <functional>
typedef double(*fn_ptr)(double);
%}

namespace std {
  // Forward declaration of result_of
  template<typename Func> struct result_of;
  // Add in a partial specialization of result_of
  template<> struct result_of< fn_ptr(double) > {
    typedef double type;
  };
}

%template() std::result_of< fn_ptr(double) >;

%inline %{

double square(double x) {
  return (x * x);
}

template<class Fun, class Arg>
typename std::result_of<Fun(Arg)>::type test_result_impl(Fun fun, Arg arg) {
  return fun(arg);
}
%}

%template(test_result) test_result_impl< fn_ptr, double >;
%constant double (*SQUARE)(double) = square;

Note the first use of %template whichSWIG requires to instantiate the template. The empty template instantiation suffices as no proxy class is required for std::result_of<Fun(Arg)>::type as this type is really just a double. The second %template instantiates the template function which is being wrapped for use as a callback. The %constant can then be used for any callback function as described in Pointers to functions and callbacks.

Example usage from Python should give the not too surprising result:

請注意,SWIG 要求實例化模板時首先使用 %template。空模板實例化就足夠了,由於 std::result_of<Fun(Arg)>::type 不須要代理類,由於這種類型實際上只是一個 double。第二個 %template 實例化模板函數,該函數被包裝以用做回調。而後,能夠將 %constant 用於任何回調函數,如函數指針與回調中所述。

來自 Python 的示例用法應該不會太使人驚訝:

>>> test_result(SQUARE, 5.0)
25.0

Phew, that is a lot of hard work to get a callback working. You could just go with the more attractive option of just using double as the return type in the function declaration instead of result_of!

唷,要使回調正常工做,有不少艱苦的工做要作。你可使用更具吸引力的選項,即在函數聲明中僅將 double 做爲返回類型,而不是 result_of