我正在尝试为一些遗留的C++代码创建python绑定,这些代码实现了它自己的“扩展”字符串类aString,它广泛使用该类。这对于.def(py::init<const std::string &, int>())来说很好,但是一旦我尝试包装重载的方法,pybind11就不会自动将std::string转换为aString。MWE从pybind11文档中改编而来:
src/example.cpp
#include <pybind11/pybind11.h>
// Extended string class and struct in legacy library
class aString : public std::string
{
public:
aString() : std::string() {}
aString(const char *str) : std::string(str) {}
aString(const std::string &str) : std::string(str) {}
};
struct Pet
{
Pet(const aString &name, int age) : name(name), age(age) {}
void set(int age_) { age = age_; }
void set(const aString &name_) { name = name_; }
aString name;
int age;
};
// Python bindings
namespace py = pybind11;
PYBIND11_MODULE(example, m)
{
py::class_<aString>(m, "aString")
.def(py::init<const std::string &>())
.def("__repr__",
[](const aString &a)
{
return "<aString ('" + a + "')>";
});
py::class_<Pet>(m, "Pet")
.def(py::init<const std::string &, int>())
.def("set", static_cast<void (Pet::*)(int)>(&Pet::set), "Set the pet's age")
.def("set", static_cast<void (Pet::*)(const aString &)>(&Pet::set), "Set the pet's name")
.def("__repr__",
[](const Pet &a)
{
return "<Pet ('" + a.name + "')>";
});
;
}CMakeLists.txt
cmake_minimum_required(VERSION 3.4)
project(example)
add_subdirectory(pybind11)
pybind11_add_module(example src/example.cpp)在python中,以下功能很好:
import example
p = example.Pet("Penny", 1)
p.set(3)
a = example.aString("Anne")
p.set(a)但是,以下消息失败:
#> p.set("Jenny")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-c5b0ff7c5315> in <module>
----> 1 p.set("Jenny")
TypeError: set(): incompatible function arguments. The following argument types are supported:
1. (self: example.Pet, arg0: int) -> None
2. (self: example.Pet, arg0: example.aString) -> None
Invoked with: <Pet ('Anne')>, 'Jenny'我尝试将我的pybinding改为.def("set", static_cast<void (Pet::*)(const std::string &)>(&Pet::set), "Set the pet's name"),而不是aString,但这不会编译,因为std::string不是重载实例之一。我不能在std:string库中为C++添加额外的重载实例。
我希望能够调用p.set("Jenny"),让pybind11将"Jenny"转换为aString("Jenny"),而不是p.set(example.aString("Jenny"))。这是我与pybind11的第一个项目,所以任何帮助都将不胜感激,谢谢!
发布于 2022-02-15 14:01:45
通过添加以下语句,可以在类型之间启用隐式转换:
py::implicitly_convertible<std::string, aString>();通常,只有当(在您的情况下) py::implicitly_convertible<A, B>()有一个以A作为其唯一参数的构造函数时,B才能工作。
发布于 2022-02-15 22:12:54
我已经将@it 1985的答案标记为正确,因为这是我最简单的解决方案--我不需要为每个方法调用手动将每个std::string转换为aString。
但是,如果任何人必须包装或添加另一种类型的重载,我确实想出了一个解决方案:
py::class_<Pet>(m, "Pet")
// ...
.def("set",
[](Pet &self, const std::string &s)
{
aString as = aString(s);
self.set(as);
});https://stackoverflow.com/questions/71124629
复制相似问题