Pythonを爆速にする「Cython」チュートリアル： C++側の関数がオーバーロードを持つとき。

##概要
C++ で書いているコードを、どうしてもPythonで呼べる形のライブラリにしたい。
ただ、そこにはCythonという大きな壁が立ちはだかっていた。

これは、[Pythonを爆速にする「Cython」チュートリアル：　C++のコードで定義したEnumクラスをPython のEnumにパースするやり方。](https://qiita.com/kenmaro/items/4c42082ce6223a69026a)　の続きになります。

コードは「[ここのgithub](https://github.com/kenmaro3/cython_practice)」にあげてあるので、ぜひご覧ください。

前回は、C++で書かれたライブラリをCython化してPythonから使えるようにする際の、C++で宣言されたEnumクラスをPython側のEnumクラスに引き渡す、というところを解説しました。


今回は、C++側の関数がオーバーロードをしているとき（同じ関数名で、引数に異なるものが入るような構成のとき）の、Cython化の解説になります。


##状況説明

これまで書いてきたライブラリの、C++側に以下のような関数を作ります。
ここで、　```print_vector```関数は、引数に ```vector<int>``` 及び```vector<double>```を取ることのできる関数であり、このようなとき関数がオーバーロードされているといいます。

```cpp_library/TestClass1.h

class TestClass1{
    private:
        TestClass2 property_test_class2;
        EnumForTestClass1 group;

    public:
        //〜省略
        static void print_vector(vector<int> x);
        static void print_vector(vector<double> x);
```

中身は以下のようにただvectorの中身をプリントする関数です。

```cpp_library/TestClass1.cpp
void TestClass1::print_vector(vector<int> x){
    for(int i=0; i<x.size(); i++){
        cout << x[i] << " ";
    }
    cout << endl;

}

void TestClass1::print_vector(vector<double> x){
    for(int i=0; i<x.size(); i++){
        cout << x[i] << " ";
    }
    cout << endl;

}
```

###Cython化
この```print_vector```関数をCythonから例のように呼ぶことを考えてみます。

```cython/my_library.pxd
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
    cdef cppclass TestClass1:
        # 〜省略
        void print_vector(vector[int] x)
        void print_vector(vector[double] x)    
```

```cython/test_class1.pxd
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
    cdef cppclass TestClass1:
        # 〜省略
        void print_vector(vector[int] x)
        void print_vector(vector[double] x)    
```

ここで、``` cython/test_class1.pyx```に中身を実装していくわけですが、

```cython/test_class1.pyx
    @staticmethod
    def print_vector(list x):
        cdef TestClass1 testclass1
        return testclass1.print_vector(x)
```

として```python setup.py install ``` を実行しようとすると、

```bash
Error compiling Cython file:
------------------------------------------------------------
...
        return testclass1.test_vector_int_ref(x,y) 

    @staticmethod
    def print_vector(list x):
        cdef TestClass1 testclass1
        return testclass1.print_vector(x)
                                     ^
------------------------------------------------------------

cython/test_class1.pyx:51:38: no suitable method found
```


とエラーが出て怒られます。。考えてみれば当たり前なのですが、C++側の``` print_vector```関数はオーバーロードされているため、
どの関数を参照しているかわからない、というわけです。
これを解決するため、キャストをして、どの関数をコールしているか明示することが必要になります。

そこで、```cython/test_class1.pyx ```を以下のように書き直します。

```cython/test_class1.pyx
    @staticmethod
    def print_vector(list x):
        cdef TestClass1 testclass1
        
        if isinstance(x[0], int):
            return testclass1.print_vector(<vector[int]>x)
        elif isinstance(x[0], float):
            return testclass1.print_vector(<vector[double]>x)
        else:
            raise Exception('TypeError')
```

これは、引数である```x```をまずは```list```と指定したあと、
その中身のタイプによってC++側のどの関数をコールするか指定しています。

実際にこのように書くと、```python setup.py install ``` でビルドできて、

```test.py
import my_library as myl

if __name__ == "__main__":

    cl1 = myl.test()
    x = [1,2,3]
    y = [1.1, 2.2, 3.3]
    cl1.print_vector(x)
    cl1.print_vector(y)
```

を実行してテストすると、

```bash
(myenv) root@e96f489c2395:/from_local/cython_practice# python test.py 
1 2 3 
1.1 2.2 3.3 
```

とうまくC++側の関数をコールできていることが分かります。



## まとめ
今回は、C++側の関数がオーバーロードをしているとき（同じ関数名で、引数に異なるものが入るような構成のとき）の、Cython化の解説をしました。


だいたい網羅してきた気がする、、あとどのようなことがC++によく書くでしょうか？
次何を書こうか現段階では決まっていないので、ネタが決まり次第次も書こうと思います。


今回はこのへんで。


おわり。