From 772c6d54d6700b54749a4f7f9ba1970974a3fc0d Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 30 Apr 2016 19:56:10 +0200 Subject: [PATCH] enable passing C++ instances to void*-valued arguments --- example/example14.cpp | 6 +++--- example/example14.py | 7 ++++++- example/example14.ref | 12 +++++++++--- include/pybind11/cast.h | 28 +++++++++++++++++++++------- include/pybind11/pybind11.h | 2 +- 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/example/example14.cpp b/example/example14.cpp index 13a20ace2..ad67fe419 100644 --- a/example/example14.cpp +++ b/example/example14.cpp @@ -49,10 +49,10 @@ void init_ex14(py::module &m) { std::cout << "]" << std::endl; }); - 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_void_ptr", []() { return (void *) 0x1234; }); + m.def("print_void_ptr", [](void *ptr) { std::cout << "Got void ptr : 0x" << std::hex << (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; }); + m.def("print_null_str", [](char *ptr) { std::cout << "Got null str : 0x" << std::hex << (uint64_t) ptr << std::endl; }); m.def("return_unique_ptr", []() -> std::unique_ptr { StringList *result = new StringList(); diff --git a/example/example14.py b/example/example14.py index 1bbe86d81..c653e0cea 100644 --- a/example/example14.py +++ b/example/example14.py @@ -33,7 +33,12 @@ print_opaque_list(cvp.stringList) ##### print_void_ptr(return_void_ptr()) -print_void_ptr(Example1()) # Should also work for other C++ types +print_void_ptr(Example1()) # Should also work for other C++ types + +try: + print_void_ptr([1, 2, 3]) # This should not work +except Exception as e: + print("Caught expected exception: " + str(e)) print(return_null_str()) print_null_str(return_null_str()) diff --git a/example/example14.ref b/example/example14.ref index 7c67b386c..c18c7ad2c 100644 --- a/example/example14.ref +++ b/example/example14.ref @@ -5,8 +5,14 @@ Back element is Element 2 Opaque list: [Element 1] Opaque list: [] Opaque list: [Element 1, Element 3] -Got void ptr : 1234 +Got void ptr : 0x1234 +Called Example1 default constructor.. +Got void ptr : 0x7f9ba0f3c430 +Called Example1 destructor (0) +Caught expected exception: Incompatible function arguments. The following argument types are supported: + 1. (capsule) -> NoneType + None -Got null str : 0 - +Got null str : 0x0 + Opaque list: [some value] diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 78e50959e..b5b3ae09a 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -52,15 +52,18 @@ PYBIND11_NOINLINE inline internals &get_internals() { return *internals_ptr; } -PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { +PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type, bool throw_if_missing = true) { auto const &type_dict = get_internals().registered_types_py; do { auto it = type_dict.find(type); if (it != type_dict.end()) return (detail::type_info *) it->second; type = type->tp_base; - if (!type) - pybind11_fail("pybind11::detail::get_type_info: unable to find type object!"); + if (!type) { + if (throw_if_missing) + pybind11_fail("pybind11::detail::get_type_info: unable to find type object!"); + return nullptr; + } } while (true); } @@ -382,11 +385,22 @@ public: value = nullptr; return true; } + + /* Check if this is a capsule */ capsule c(h, true); - if (!c.check()) - return false; - value = (void *) c; - return true; + if (c.check()) { + value = (void *) c; + return true; + } + + /* Check if this is a C++ type */ + if (get_type_info((PyTypeObject *) h.get_type().ptr(), false)) { + value = ((instance *) h.ptr())->value; + return true; + } + + /* Fail */ + return false; } static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 7c3642115..4706b6f7c 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -450,7 +450,7 @@ protected: return nullptr; } else { if (overloads->is_constructor) { - /* When a construtor ran successfully, the corresponding + /* When a constructor ran successfully, the corresponding holder type (e.g. std::unique_ptr) must still be initialized. */ PyObject *inst = PyTuple_GetItem(args, 0); auto tinfo = detail::get_type_info(Py_TYPE(inst));