diff --git a/example/example14.cpp b/example/example14.cpp index f7f176a18..6a33ba775 100644 --- a/example/example14.cpp +++ b/example/example14.cpp @@ -29,4 +29,6 @@ void init_ex14(py::module &m) { m.def("return_void_ptr", []() { return (void *) 1234; }); m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : " << (uint64_t) ptr << std::endl; }); + m.def("return_null_str", []() { return (char *) nullptr; }); + m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : " << (uint64_t) ptr << std::endl; }); } diff --git a/example/example14.py b/example/example14.py index aef9923f0..08f5d46a5 100644 --- a/example/example14.py +++ b/example/example14.py @@ -4,6 +4,8 @@ import sys sys.path.append('.') from example import StringList, print_opaque_list +from example import return_void_ptr, print_void_ptr +from example import return_null_str, print_null_str l = StringList() l.push_back("Element 1") @@ -13,6 +15,7 @@ print("Back element is %s" % l.back()) l.pop_back() print_opaque_list(l) -from example import return_void_ptr, print_void_ptr - print_void_ptr(return_void_ptr()) + +print(return_null_str()) +print_null_str(return_null_str()) diff --git a/example/example14.ref b/example/example14.ref index 38a27e173..7554a5ebd 100644 --- a/example/example14.ref +++ b/example/example14.ref @@ -5,3 +5,5 @@ Back element is Element 2 Opaque list: Element 1 Got void ptr : 1234 +None +Got null str : 0 diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index dddd40a2c..5ddfdf76f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -391,6 +391,7 @@ public: int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(load_src.ptr(), &buffer, &length); if (err == -1) { PyErr_Clear(); return false; } // TypeError value = std::string(buffer, length); + success = true; return true; } @@ -399,6 +400,8 @@ public: } PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; }; template <> class type_caster { @@ -428,6 +431,7 @@ public: #endif if (!buffer) { PyErr_Clear(); return false; } value = std::wstring(buffer, length); + success = true; return true; } @@ -436,11 +440,19 @@ public: } PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); +protected: + bool success = false; }; template <> class type_caster : public type_caster { public: + bool load(handle src, bool convert) { + if (src.ptr() == Py_None) { return true; } + return type_caster::load(src, convert); + } + static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return handle(Py_None).inc_ref(); return PyUnicode_FromString(src); } @@ -449,18 +461,21 @@ public: return PyUnicode_DecodeLatin1(str, 1, nullptr); } - operator char*() { return (char *) value.c_str(); } - operator char() { if (value.length() > 0) return value[0]; else return '\0'; } - - template - using cast_op_type = typename std::conditional::value, char*, char>::type; + operator char*() { return success ? (char *) value.c_str() : nullptr; } + operator char&() { return value[0]; } static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } }; template <> class type_caster : public type_caster { public: + bool load(handle src, bool convert) { + if (src.ptr() == Py_None) { return true; } + return type_caster::load(src, convert); + } + static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { + if (src == nullptr) return handle(Py_None).inc_ref(); return PyUnicode_FromWideChar(src, wcslen(src)); } @@ -469,8 +484,8 @@ public: return PyUnicode_FromWideChar(wstr, 1); } - operator wchar_t*() { return (wchar_t *)value.c_str(); } - operator wchar_t() { if (value.length() > 0) return value[0]; else return L'\0'; } + operator wchar_t*() { return success ? (wchar_t *) value.c_str() : nullptr; } + operator wchar_t&() { return value[0]; } static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } };