# 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.

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.

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:

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:

%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:

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:

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:

%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:

%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:

>>> 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:

%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 onto std::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.

### 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:

>>> 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:

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.

### 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.

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:

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:

>>> 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:

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:

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.

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

int value = 5;
};


### 7.2.11 显式 overrides 与 final

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

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.

### 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

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:

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:

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.

### 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 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](http://SWIG.org/Doc3.0/ SWIG Plus.html# SWIG Plus_nn30) section for more general information on wrapping templates.

### 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(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:

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


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

### 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 =        ")Im an \"ascii\" \\ string.";
const char      *ee =   R"XXX()Im an "ascii" \ string.)XXX"; // same as xx
wstring          ff =  LR"XXX(Im a "raw wide" \ string.)XXX";
const char      *gg = u8R"XXX(Im a "raw UTF-8" \ string.)XXX";
const char16_t  *hh =  uR"XXX(Im a "raw UTF-16" \ string.)XXX";
const char32_t  *ii =  UR"XXX(Im 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.

### 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:

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(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 {
};


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.

### 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:

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.

### 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:

>>> 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:

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.

### 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.

### 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.

### 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.

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:

#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:

>>> 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:

>>> 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!

posted @ 2019-12-23 21:58  xuruilong100  阅读(...)  评论(...编辑  收藏