使用pybind11和std :: filesystem作为函数参数的Python绑定,给出TypeError

时间:2019-05-06 17:43:56

标签: c++17 pybind11 std-filesystem

我有一个Foo()类,而Foo()类具有一个带有以下声明的函数:

bool Foo::copyFile(const std::filesystem::path& src, const std::filesystem::path& dest)

要求是Foo类应具有Python绑定。我正在使用pybind11创建Python绑定。

我编写了以下代码来创建Python绑定:

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "Foo.h"

namespace py = pybind11;

PYBIND11_MODULE(TestModule, m) {
     py::class_ <Foo>(m, "Foo")
        .def(py::init())
        .def("copyFile",&Foo::copyFile);
};

这将编译确定,并且我能够创建Python绑定pyd文件。 当我使用Foo类的Python绑定时:

from TestModule import Foo

f = Foo()
ret = f.copyFile("C:\Users\csaikia\Downloads\testfile_src", "C:\Users\csaikia\Downloads\testfile_dest")

它给出TypeError。我怀疑这与pybind11对c ++ 17中的std :: filesystem的支持有关,因为我没有看到这种情况在具有std::stringstd::vector的类的其他函数中发生。 >

我得到的错误是:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: copyFile(): incompatible function arguments. The following argument types are supported:
    1. (self: TestModule.Foo, arg0: std::filesystem::path, arg1: std::filesystem::path) -> bool

Invoked with: <TestModule.Foo object at 0x0000000002A33ED8>,  'C:\\Users\\csaikia\\Downloads\\testfile_src', 'C:\\Users\\csaikia\\Downloads\\testfile_dest'

Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.

我是pybind11的新手。有人可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

从我与pybind11开发人员的对话中:

“ Pybind不知道如何将py::str转换为std::filesystem::path。没有可用的Caster,也没有绑定std::filesystem::path类。

最简单的方法是不直接绑定Foo::copyFile。而是绑定一个接受const Foo&const std::string&作为参数的lambda,然后可以将std::string传递到copyFile所在的std::filesystem::path,让C ++隐式转换发生

您也可以进行py::class_<std::filesystem::path>并为std::string转换器建立绑定,然后使用py::implicitly_convertible让所有C ++隐式构造都在python端进行,但是... ,工作量过多。”

它就像一种魅力!

答案 1 :(得分:0)

只需将以下几行添加到您的绑定中(假设py::module& m)。

py::class_<std::filesystem::path>(m, "Path")
    .def(py::init<std::string>());
py::implicitly_convertible<std::string, std::filesystem::path>();

这是基于@ user304255描述的后一种方法。