GO 1.5 と C++ を SWIG でブリッジさせる方法

わかってしまえば簡単なのだが、引っかかることが多いのでメモ。
（検証環境：OSX El Capitan, GO 1.5.1, SWIG 3.0.7）

***
#１　まず引数をエコーさせる単純な例を考える。

ソースディレクトリに以下の3ファイルを作る。

```cpp:sc1.h
#pragma once 

inline	int
EchoIntN( int p ) {
	return p;
}

inline	double
EchoDoubleN( double p ) {
	return p;
}
```

```sc1.swigcxx
%module	sc1
%{
#include	"sc1.h"
%}

%include	"sc1.h"
```

```go:nop.go
package sc1
```

以下を実行すると

> go install

*. swigcxx　があれば自動的に swig が呼び出され、pkg 化されてインストールされる。（GO 1.5 から）
ファイル nop.go は go ファイルが一つもないと go install が失敗してしまうので、その対策用のダミー。他に go ファイルがあれば必要ない。

呼び出し側は実行ディレクトリに以下のファイルを用意して

```main1.go
package main

import	"fmt"
import	"github.com/Satachito/sc1"

func
Dump( p interface{} ) {
	fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
	Dump( sc1.EchoIntN( 8 ) );
	Dump( sc1.EchoDoubleN( 9 ) );
}
```

実行

> $ go run main1.go
> 8:int
> 9:float64



***
補足

もし nop.go ファイルを作るのが嫌だったら、sc1.swigcxx を別の名前（例えばsc1.i）に変えて、明示的に swig を呼び出してから go install すれば良い。

> swig -go -c++ -cgo -intgosize 32 sc1.i
> go install

sc1.go と sc1_wrap.cxx の２つのファイルが同一ディレクトリに作成される。

***
#２　テンプレート化してみる。

```cpp:sc2.h
#pragma once 

template	<typename T>	T
Echo( const T& p ) {
	return p;
}
```

```sc2.swigcxx
%module	sc2
%{
#include "sc2.h"
%}

%include "sc2.h"

%template(EchoIntT) 	Echo<int>;
%template(EchoDoubleT) 	Echo<double>;
```
最後の２行でテンプレートを実体化している。

```go:nop.go
package sc2
```

として

> go install

呼び出し側は

```go:main2.go
package main

import	"fmt"
import	"github.com/Satachito/sc2"

func
Dump( p interface{} ) {
	fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
	Dump( sc2.EchoIntT( 8 ) );
	Dump( sc2.EchoDoubleT( 9 ) );
}

```

> $ go run main2.go
> 8:int
> 9:float64

***
#３　string を使ってみる。
関数とテンプレート両方用意した。

```cpp:sc3.h
#pragma once 

template	<typename T>	T
Echo( const T& p ) {
	return p;
}

#include	<string>

inline	std::string
EchoStringN( std::string p ) {
	return p;
}
```

```sc3.swigcxx
%module	sc3
%{
#include "sc3.h"
%}


%include	"std_string.i"

%include	"sc3.h"

%template(EchoStringT)	Echo<std::string>;

```
std_string.i を include するのがポイント

```go:nop.go
package sc3
```

として

> go install

呼び出し側は

```go:main3.go
package main

import	"fmt"
import	"github.com/Satachito/sc3"

func
Dump( p interface{} ) {
	fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
	Dump( sc3.EchoStringN( "Echo me N." ) );
	Dump( sc3.EchoStringT( "Echo me T." ) );
}
```

> $ go run main3.go
> Echo me N.:string
> Echo me T.:string


***
#４　vector を使ってみる。


```cpp:sc4.h
#pragma once 

template	<typename T>	T
Echo( const T& p ) {
	return p;
}

#include	<string>
#include	<vector>

inline	std::vector<std::string>
EchoVSN( std::vector<std::string> p ) {
	return p;
}
```

```sc4.swigcxx
%module	sc4
%{
#include "sc4.h"
%}


%include	"std_string.i"
%include	"std_vector.i"

%include	"sc4.h"

namespace std {
	%template(StringVector) vector<string>;
}

%template(EchoVST)	Echo<std::vector<std::string>>;
```
std_vetor.i を include するのがポイント。

```go:nop.go
package sc4
```

として

> go install

呼び出し側は

```go:main4.go
package main

import	"fmt"
import	"github.com/Satachito/sc4"

func
Dump( p interface{} ) {
	fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
	a := sc4.NewStringVector()
	defer sc4.DeleteStringVector( a )
	a.Add( "Echo me." );
	Dump( sc4.EchoVSN( a ).Get( 0 ) );
	Dump( sc4.EchoVST( a ).Get( 0 ) );
}
```

> $ go run main4.go
Echo me.:string
Echo me.:string

NewStringVector, DeleteStringVector, Add, Get は自動的に生成されている。他にもvectorとして扱うために必要なものが生成される。どんなメソッドが生成されているかを見るには、swig を明示的に呼び出して生成された go ファイルの中を見てみる。


***
#５　struct を使ってみる。


```cpp:sc5.h
#pragma once 

template	<typename T>	T
Echo( const T& p ) {
	return p;
}

struct
IF {
	int		I;
	float	F;
	double	Total() {
		return I + F;
	}
};

IF
EchoIFN( const IF& p ) {
	return p;
}
```

```sc5.swigcxx
%module	sc5
%{
#include "sc5.h"
%}

%include	"sc5.h"

%template(EchoIFT)	Echo<IF>;
```

```go:nop.go
package sc5
```

として

> go install

呼び出し側は

```go:main5.go
package main

import	"fmt"
import	"github.com/Satachito/sc5"

func
Dump( p interface{} ) {
	fmt.Printf( "%v:%T\n", p, p )
}

func
main() {
	a := sc5.NewIF()
	defer sc5.DeleteIF( a )
	a.SetI( 1 )
	a.SetF( 2 )
	w1 := sc5.EchoIFN( a )
	Dump( w1.GetI() );
	Dump( w1.GetF() );
	Dump( w1.Total() );
	w2 := sc5.EchoIFT( a )
	Dump( w2.GetI() );
	Dump( w2.GetF() );
	Dump( w2.Total() );
}
```

> $ go run main5.go
1:int
2:float32
3:float64
1:int
2:float32
3:float64

メンバーには直接アクセスできないので、setter, getter を使う。
忘れがちだけど、GO らしく C の構造体の方のメンバーの名前も最初大文字で。
***