Defining a custom string class #4685
-
Hey there, i really love this library, but I have an issue what i think should be possible. Consider following code: #include <iostream>
#include <chrono>
#include <pybind11/stl.h>
#include <pybind11/embed.h>
namespace py = pybind11;
class Object {
public:
Object() = default;
std::string label;
};
PYBIND11_EMBEDDED_MODULE(b, m) {
py::class_<Object>(m, "Object")
.def(py::init<>())
.def_readwrite("label", &Object::label);
}
int main() {
py::scoped_interpreter guard{}; // start the interpreter and keep it alive
try {
py::exec(
"import b\n"
"obj = b.Object()\n"
"obj.label = 'Hello World'\n"
"print(obj.label)\n"
);
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
} I have an object with a string property, that can be assigned and read from. perfect. But now i want to replace it with my own custom class: #include <iostream>
#include <chrono>
#include <pybind11/stl.h>
#include <pybind11/embed.h>
namespace py = pybind11;
class String : public std::string {
public:
String() = default;
String(const std::string& s) : std::string(s) { }
operator std::string() { return *this; }
String& operator=(const std::string& s) { std::string::operator=(s); return *this; }
};
class Object {
public:
Object() = default;
String label;
};
PYBIND11_EMBEDDED_MODULE(b, m) {
py::class_<String>(m, "String")
.def(py::init<>())
.def(py::init<const std::string&>())
// SOME MACIGAL FUNCTIONS HERE
.def("__str__", [](String& s) { return s; })
.def("__repr__", [](String& s) { return s; })
.def("__eq__", [](String& s, const std::string& o) { return s == o; });
py::class_<Object>(m, "Object")
.def(py::init<>())
.def_readwrite("label", &Object::label);
}
int main() {
py::scoped_interpreter guard{}; // start the interpreter and keep it alive
try {
py::exec(
"import b\n"
"obj = b.Object()\n"
"obj.label = 'Hello World'\n"
"print(obj.label)\n"
);
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
} The string class should be a 1-to-1 drop-in replacement of std::string, so no change to the Object.
What am i missing to tell pybind11 to do this? I really searched a lot and also asked ChatGPT a gazillion times, but no luck. Any help apprechiated... |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
The answer really always comes up just after asking in a forum. namespace pybind11::detail {
template <> struct type_caster<String> : public type_caster_base<String> {
using base = type_caster_base<String>;
public:
bool load(handle src, bool convert) {
if (base::load(src, convert)) {
return true;
}
else if (py::isinstance<py::str>(src)) {
value = new String(py::cast<std::string>(src));
return true;
}
return false;
}
static handle cast(const String& src, return_value_policy policy, handle parent) {
return py::cast(std::string(src), policy, parent).release();
}
};
} |
Beta Was this translation helpful? Give feedback.
The answer really always comes up just after asking in a forum.
What does the trick for me: