pybind11の引数の型に注意。

 自作ライブラリのPythonラッパーを作るためにpybind11を導入している私だが、関数引数の型についていくつかのエラーに悩まされたので、備忘録として記しておく。

デフォルト引数の型が適切かどうかはコンパイル時に判定されない。

void func(const std::vector<double>&) {}
m.def("func", &func, "vector"_a = "");

 ある関数funcがあったとして、それのデフォルト引数に空文字列""を指定したとする。空文字列からstd::vectorへの変換はできないので、これはコンパイルエラーになるかと思いきや、ならない。Pythonでの実行時に初めて、型の指定が間違っていて関数を呼べないとエラーメッセージが表示される。
 引数が20個くらいある関数のデフォルト引数の型の誤りに気付けず一時間くらい悩んだ。

引数の暗黙型変換は(自動的には)行われない。

struct A
{
    A(const std::string&) {}
}
void func(A a) {}

py::class_<A>(m, "A").
    def(py::init<>());
m.def("func", &func);

 このようにラップされた関数funcがあったとする。C++ではfuncに対してconst char*やstd::stringを与えた時にコンストラクタを介した暗黙の型変換によって勝手に呼ぶべき関数を判定してくれるが、Pybind11はそのままでは型の変換が行われず、Pythonの実行時に関数呼び出し失敗のエラーが生じる。

func("test")
-> incompatible function arguments. The following argument types are supported...

 暗黙の型変換を有効にするには、次のように予め定義しておく必要がある。

py::implicitly_convertible<std::string, A>();