From ba08db4da5c8fc105714ddfc623db6bd67a4eefd Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:09:10 +0100 Subject: [PATCH 1/9] Import a few more numpy extern symbols --- include/pybind11/numpy.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 04001d6c5..aa93c5500 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -103,7 +103,9 @@ struct npy_api { PyObject *(*PyArray_DescrNewFromType_)(int); PyObject *(*PyArray_NewCopy_)(PyObject *, int); PyTypeObject *PyArray_Type_; + PyTypeObject *PyVoidArrType_Type_; PyTypeObject *PyArrayDescr_Type_; + PyObject *(*PyArray_DescrFromScalar_)(PyObject *); PyObject *(*PyArray_FromAny_) (PyObject *, PyObject *, int, int, int, PyObject *); int (*PyArray_DescrConverter_) (PyObject *, PyObject **); bool (*PyArray_EquivTypes_) (PyObject *, PyObject *); @@ -114,7 +116,9 @@ private: enum functions { API_PyArray_Type = 2, API_PyArrayDescr_Type = 3, + API_PyVoidArrType_Type = 39, API_PyArray_DescrFromType = 45, + API_PyArray_DescrFromScalar = 57, API_PyArray_FromAny = 69, API_PyArray_NewCopy = 85, API_PyArray_NewFromDescr = 94, @@ -136,8 +140,10 @@ private: npy_api api; #define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func]; DECL_NPY_API(PyArray_Type); + DECL_NPY_API(PyVoidArrType_Type); DECL_NPY_API(PyArrayDescr_Type); DECL_NPY_API(PyArray_DescrFromType); + DECL_NPY_API(PyArray_DescrFromScalar); DECL_NPY_API(PyArray_FromAny); DECL_NPY_API(PyArray_NewCopy); DECL_NPY_API(PyArray_NewFromDescr); From c275ee6b4620315d24c2251c1eea3bb66253eb61 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:09:31 +0100 Subject: [PATCH 2/9] Add support for "direct" converters --- include/pybind11/cast.h | 13 +++++++++++-- include/pybind11/common.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 91912de75..46d202a82 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -157,7 +157,7 @@ inline void keep_alive_impl(handle nurse, handle patient); class type_caster_generic { public: PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) - : typeinfo(get_type_info(type_info, false)) { } + : typeinfo(get_type_info(type_info, false)), tindex(type_info) { } PYBIND11_NOINLINE bool load(handle src, bool convert) { if (!src) @@ -208,13 +208,21 @@ public: } } - /* Perform an implicit conversion */ + /* Perform an implicit or a direct conversion */ if (convert) { for (auto &converter : typeinfo->implicit_conversions) { temp = object(converter(src.ptr(), typeinfo->type), false); if (load(temp, false)) return true; } + auto& direct = get_internals().direct_conversions; + auto it = direct.find(tindex); + if (it != direct.end()) { + for (auto& converter : it->second) { + if (converter(src.ptr(), value)) + return true; + } + } } return false; } @@ -294,6 +302,7 @@ public: protected: const type_info *typeinfo = nullptr; + std::type_index tindex; void *value = nullptr; object temp; }; diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 40cee8703..be4633ccd 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -321,6 +321,7 @@ struct internals { std::unordered_map registered_types_py; // PyTypeObject* -> type_info std::unordered_multimap registered_instances; // void * -> PyObject* std::unordered_set, overload_hash> inactive_overload_cache; + std::unordered_map> direct_conversions; std::forward_list registered_exception_translators; #if defined(WITH_THREAD) decltype(PyThread_create_key()) tstate = 0; // Usually an int but a long on Cygwin64 with Python 3.x From 7bf90e8008fcaba6b03dfbc999610928197174fa Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:11:08 +0100 Subject: [PATCH 3/9] Add a direct converter for numpy scalars --- include/pybind11/numpy.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index aa93c5500..dba8b7a2b 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -63,6 +63,14 @@ struct PyArray_Proxy { int flags; }; +struct PyVoidScalarObject_Proxy { + PyObject_VAR_HEAD + char *obval; + PyArrayDescr_Proxy *descr; + int flags; + PyObject *base; +}; + struct npy_api { enum constants { NPY_C_CONTIGUOUS_ = 0x0001, @@ -702,11 +710,29 @@ struct npy_format_descriptor::value>> { auto arr = array(buffer_info(nullptr, sizeof(T), format(), 1)); if (!api.PyArray_EquivTypes_(dtype_ptr, arr.dtype().ptr())) pybind11_fail("NumPy: invalid buffer descriptor!"); + + register_direct_converter(); } private: static std::string format_str; static PyObject* dtype_ptr; + + static void register_direct_converter() { + auto converter = [=](PyObject *obj, void*& value) { + auto& api = npy_api::get(); + if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) + return false; + if (auto descr = object(api.PyArray_DescrFromScalar_(obj), false)) { + if (api.PyArray_EquivTypes_(dtype_ptr, descr.ptr())) { + value = ((PyVoidScalarObject_Proxy *) obj)->obval; + return true; + } + } + return false; + }; + get_internals().direct_conversions[std::type_index(typeid(T))].push_back(converter); + } }; template From 85e16262d622cce52a0352bc125b5cf1d17cac6f Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:46:40 +0100 Subject: [PATCH 4/9] Enable direct conversions with no typeinfo present --- include/pybind11/cast.h | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 46d202a82..ad2d14b8f 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -166,12 +166,14 @@ public: } bool load(handle src, bool convert, PyTypeObject *tobj) { - if (!src || !typeinfo) + if (!src) return false; if (src.is_none()) { value = nullptr; return true; } + if (!typeinfo) + return load_direct(src, convert); if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ /* Check if we can safely perform a reinterpret-style cast */ @@ -208,23 +210,16 @@ public: } } - /* Perform an implicit or a direct conversion */ + /* Perform an implicit conversion */ if (convert) { for (auto &converter : typeinfo->implicit_conversions) { temp = object(converter(src.ptr(), typeinfo->type), false); if (load(temp, false)) return true; } - auto& direct = get_internals().direct_conversions; - auto it = direct.find(tindex); - if (it != direct.end()) { - for (auto& converter : it->second) { - if (converter(src.ptr(), value)) - return true; - } - } } - return false; + + return load_direct(src, convert); } PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, @@ -305,6 +300,20 @@ protected: std::type_index tindex; void *value = nullptr; object temp; + + bool load_direct(handle src, bool convert) { + if (convert) { + auto& direct = get_internals().direct_conversions; + auto it = direct.find(tindex); + if (it != direct.end()) { + for (auto& converter : it->second) { + if (converter(src.ptr(), value)) + return true; + } + } + } + return false; + } }; /* Determine suitable casting operator */ From cbbb7830f2f9953d3ea52b4e0f31828da4a6936b Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:47:29 +0100 Subject: [PATCH 5/9] Add a test for NumPy scalar conversion --- tests/test_numpy_dtypes.cpp | 11 +++++++++++ tests/test_numpy_dtypes.py | 22 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 86e6e68cc..043d41b47 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -298,6 +298,9 @@ test_initializer numpy_dtypes([](py::module &m) { return; } + // typeinfo may be registered before the dtype descriptor for scalar casts to work... + py::class_(m, "SimpleStruct"); + PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z); PYBIND11_NUMPY_DTYPE(PackedStruct, x, y, z); PYBIND11_NUMPY_DTYPE(NestedStruct, a, b); @@ -306,6 +309,11 @@ test_initializer numpy_dtypes([](py::module &m) { PYBIND11_NUMPY_DTYPE(StringStruct, a, b); PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); + // ... or after... + py::class_(m, "PackedStruct"); + + // ... or not at all + m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray); m.def("create_rec_nested", &create_nested); @@ -324,6 +332,9 @@ test_initializer numpy_dtypes([](py::module &m) { m.def("test_array_ctors", &test_array_ctors); m.def("test_dtype_ctors", &test_dtype_ctors); m.def("test_dtype_methods", &test_dtype_methods); + m.def("f_simple", [](SimpleStruct s) { return s.y * 10; }); + m.def("f_packed", [](PackedStruct s) { return s.y * 10; }); + m.def("f_nested", [](NestedStruct s) { return s.a.y * 10; }); }); #undef PYBIND11_PACKED diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 22f5c662f..322400296 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -174,3 +174,25 @@ def test_signature(doc): from pybind11_tests import create_rec_nested assert doc(create_rec_nested) == "create_rec_nested(arg0: int) -> numpy.ndarray[NestedStruct]" + + +@pytest.requires_numpy +def test_scalar_conversion(): + from pybind11_tests import (create_rec_simple, f_simple, + create_rec_packed, f_packed, + create_rec_nested, f_nested, + create_enum_array) + + n = 3 + arrays = [create_rec_simple(n), create_rec_packed(n), + create_rec_nested(n), create_enum_array(n)] + funcs = [f_simple, f_packed, f_nested] + + for i, func in enumerate(funcs): + for j, arr in enumerate(arrays): + if i == j: + assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)] + else: + with pytest.raises(TypeError) as excinfo: + func(arr[0]) + assert 'incompatible function arguments' in str(excinfo.value) From ccc69f91f46115bcc9def5c9d4fba8ff03745190 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:52:24 +0100 Subject: [PATCH 6/9] Cache direct converters in the generic type caster --- include/pybind11/cast.h | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index ad2d14b8f..1d6f605dd 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -157,7 +157,8 @@ inline void keep_alive_impl(handle nurse, handle patient); class type_caster_generic { public: PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) - : typeinfo(get_type_info(type_info, false)), tindex(type_info) { } + : typeinfo(get_type_info(type_info, false)), + direct_conversions(get_internals().direct_conversions[std::type_index(type_info)]) { } PYBIND11_NOINLINE bool load(handle src, bool convert) { if (!src) @@ -297,19 +298,15 @@ public: protected: const type_info *typeinfo = nullptr; - std::type_index tindex; + const std::vector& direct_conversions; void *value = nullptr; object temp; bool load_direct(handle src, bool convert) { if (convert) { - auto& direct = get_internals().direct_conversions; - auto it = direct.find(tindex); - if (it != direct.end()) { - for (auto& converter : it->second) { - if (converter(src.ptr(), value)) - return true; - } + for (auto& converter : direct_conversions) { + if (converter(src.ptr(), value)) + return true; } } return false; From 7edd72db243e676514d8e036e2688fa96e573343 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Thu, 20 Oct 2016 16:57:12 +0100 Subject: [PATCH 7/9] Disallow registering dtypes multiple times --- include/pybind11/numpy.h | 3 +++ tests/test_numpy_dtypes.cpp | 1 + tests/test_numpy_dtypes.py | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index dba8b7a2b..602d703cb 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -668,6 +668,9 @@ struct npy_format_descriptor::value>> { } static void register_dtype(std::initializer_list fields) { + if (dtype_ptr) + pybind11_fail("NumPy: dtype is already registered"); + list names, formats, offsets; for (auto field : fields) { if (!field.descr) diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index 043d41b47..f85195353 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -335,6 +335,7 @@ test_initializer numpy_dtypes([](py::module &m) { m.def("f_simple", [](SimpleStruct s) { return s.y * 10; }); m.def("f_packed", [](PackedStruct s) { return s.y * 10; }); m.def("f_nested", [](NestedStruct s) { return s.a.y * 10; }); + m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, x, y, z); }); }); #undef PYBIND11_PACKED diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 322400296..0503ef1a9 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -196,3 +196,12 @@ def test_scalar_conversion(): with pytest.raises(TypeError) as excinfo: func(arr[0]) assert 'incompatible function arguments' in str(excinfo.value) + + +@pytest.requires_numpy +def test_register_dtype(): + from pybind11_tests import register_dtype + + with pytest.raises(RuntimeError) as excinfo: + register_dtype() + assert 'dtype is already registered' in str(excinfo.value) From a6e6a8b108f49f8e990045e020e2058b15dfcf5b Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Sun, 23 Oct 2016 15:27:13 +0100 Subject: [PATCH 8/9] Require existing typeinfo for direct conversions This avoid a hashmap lookup since the pointer to the list of direct converters is now cached in the typeinfo. --- include/pybind11/cast.h | 26 ++++++++------------------ include/pybind11/numpy.h | 27 ++++++++++++++------------- include/pybind11/pybind11.h | 1 + tests/test_numpy_dtypes.cpp | 4 +--- tests/test_numpy_dtypes.py | 2 +- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1d6f605dd..1b82d44f4 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -26,6 +26,7 @@ struct type_info { void (*init_holder)(PyObject *, const void *); std::vector implicit_conversions; std::vector> implicit_casts; + std::vector *direct_conversions; buffer_info *(*get_buffer)(PyObject *, void *) = nullptr; void *get_buffer_data = nullptr; /** A simple type never occurs as a (direct or indirect) parent @@ -157,8 +158,7 @@ inline void keep_alive_impl(handle nurse, handle patient); class type_caster_generic { public: PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) - : typeinfo(get_type_info(type_info, false)), - direct_conversions(get_internals().direct_conversions[std::type_index(type_info)]) { } + : typeinfo(get_type_info(type_info, false)) { } PYBIND11_NOINLINE bool load(handle src, bool convert) { if (!src) @@ -167,14 +167,12 @@ public: } bool load(handle src, bool convert, PyTypeObject *tobj) { - if (!src) + if (!src || !typeinfo) return false; if (src.is_none()) { value = nullptr; return true; } - if (!typeinfo) - return load_direct(src, convert); if (typeinfo->simple_type) { /* Case 1: no multiple inheritance etc. involved */ /* Check if we can safely perform a reinterpret-style cast */ @@ -218,9 +216,12 @@ public: if (load(temp, false)) return true; } + for (auto &converter : *typeinfo->direct_conversions) { + if (converter(src.ptr(), value)) + return true; + } } - - return load_direct(src, convert); + return false; } PYBIND11_NOINLINE static handle cast(const void *_src, return_value_policy policy, handle parent, @@ -298,19 +299,8 @@ public: protected: const type_info *typeinfo = nullptr; - const std::vector& direct_conversions; void *value = nullptr; object temp; - - bool load_direct(handle src, bool convert) { - if (convert) { - for (auto& converter : direct_conversions) { - if (converter(src.ptr(), value)) - return true; - } - } - return false; - } }; /* Determine suitable casting operator */ diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h index 602d703cb..2db3de273 100644 --- a/include/pybind11/numpy.h +++ b/include/pybind11/numpy.h @@ -721,20 +721,21 @@ private: static std::string format_str; static PyObject* dtype_ptr; - static void register_direct_converter() { - auto converter = [=](PyObject *obj, void*& value) { - auto& api = npy_api::get(); - if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) - return false; - if (auto descr = object(api.PyArray_DescrFromScalar_(obj), false)) { - if (api.PyArray_EquivTypes_(dtype_ptr, descr.ptr())) { - value = ((PyVoidScalarObject_Proxy *) obj)->obval; - return true; - } - } + static bool direct_converter(PyObject *obj, void*& value) { + auto& api = npy_api::get(); + if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) return false; - }; - get_internals().direct_conversions[std::type_index(typeid(T))].push_back(converter); + if (auto descr = object(api.PyArray_DescrFromScalar_(obj), false)) { + if (api.PyArray_EquivTypes_(dtype_ptr, descr.ptr())) { + value = ((PyVoidScalarObject_Proxy *) obj)->obval; + return true; + } + } + return false; + } + + static void register_direct_converter() { + get_internals().direct_conversions[std::type_index(typeid(T))].push_back(direct_converter); } }; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 752f77564..ffa25801b 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -672,6 +672,7 @@ protected: tinfo->type = (PyTypeObject *) type; tinfo->type_size = rec->type_size; tinfo->init_holder = rec->init_holder; + tinfo->direct_conversions = &internals.direct_conversions[tindex]; internals.registered_types_cpp[tindex] = tinfo; internals.registered_types_py[type] = tinfo; diff --git a/tests/test_numpy_dtypes.cpp b/tests/test_numpy_dtypes.cpp index f85195353..40aca0c3c 100644 --- a/tests/test_numpy_dtypes.cpp +++ b/tests/test_numpy_dtypes.cpp @@ -309,11 +309,9 @@ test_initializer numpy_dtypes([](py::module &m) { PYBIND11_NUMPY_DTYPE(StringStruct, a, b); PYBIND11_NUMPY_DTYPE(EnumStruct, e1, e2); - // ... or after... + // ... or after py::class_(m, "PackedStruct"); - // ... or not at all - m.def("create_rec_simple", &create_recarray); m.def("create_rec_packed", &create_recarray); m.def("create_rec_nested", &create_nested); diff --git a/tests/test_numpy_dtypes.py b/tests/test_numpy_dtypes.py index 0503ef1a9..47d7c3bd7 100644 --- a/tests/test_numpy_dtypes.py +++ b/tests/test_numpy_dtypes.py @@ -190,7 +190,7 @@ def test_scalar_conversion(): for i, func in enumerate(funcs): for j, arr in enumerate(arrays): - if i == j: + if i == j and i < 2: assert [func(arr[k]) for k in range(n)] == [k * 10 for k in range(n)] else: with pytest.raises(TypeError) as excinfo: From 8f3e045deb6d504e202d9e57318b6c5d8fd691e6 Mon Sep 17 00:00:00 2001 From: Ivan Smirnov Date: Sun, 23 Oct 2016 15:43:03 +0100 Subject: [PATCH 9/9] Use detail::get_type_info() wherever sensible This reduces direct access to internals.registered_types_cpp to just a few places. --- include/pybind11/cast.h | 5 +++-- include/pybind11/pybind11.h | 25 +++++++++---------------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 1b82d44f4..86a2f4ad1 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -91,7 +91,8 @@ PYBIND11_NOINLINE inline detail::type_info* get_type_info(PyTypeObject *type) { } while (true); } -PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp, bool throw_if_missing) { +PYBIND11_NOINLINE inline detail::type_info *get_type_info(const std::type_info &tp, + bool throw_if_missing = false) { auto &types = get_internals().registered_types_cpp; auto it = types.find(std::type_index(tp)); @@ -158,7 +159,7 @@ inline void keep_alive_impl(handle nurse, handle patient); class type_caster_generic { public: PYBIND11_NOINLINE type_caster_generic(const std::type_info &type_info) - : typeinfo(get_type_info(type_info, false)) { } + : typeinfo(get_type_info(type_info)) { } PYBIND11_NOINLINE bool load(handle src, bool convert) { if (!src) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index ffa25801b..68287e05a 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -180,8 +180,6 @@ protected: a.descr = strdup(a.value.attr("__repr__")().cast().c_str()); } - auto const ®istered_types = detail::get_internals().registered_types_cpp; - /* Generate a proper function signature */ std::string signature; size_t type_depth = 0, char_index = 0, type_index = 0, arg_index = 0; @@ -216,9 +214,8 @@ protected: const std::type_info *t = types[type_index++]; if (!t) pybind11_fail("Internal error while parsing type signature (1)"); - auto it = registered_types.find(std::type_index(*t)); - if (it != registered_types.end()) { - signature += ((const detail::type_info *) it->second)->type->tp_name; + if (auto tinfo = detail::get_type_info(*t)) { + signature += tinfo->type->tp_name; } else { std::string tname(t->name()); detail::clean_type_id(tname); @@ -610,8 +607,7 @@ protected: auto &internals = get_internals(); auto tindex = std::type_index(*(rec->type)); - if (internals.registered_types_cpp.find(tindex) != - internals.registered_types_cpp.end()) + if (get_type_info(*(rec->type))) pybind11_fail("generic_type: type \"" + std::string(rec->name) + "\" is already registered!"); @@ -1334,11 +1330,11 @@ template void implicitly_convertible() PyErr_Clear(); return result; }; - auto ®istered_types = detail::get_internals().registered_types_cpp; - auto it = registered_types.find(std::type_index(typeid(OutputType))); - if (it == registered_types.end()) + + if (auto tinfo = detail::get_type_info(typeid(OutputType))) + tinfo->implicit_conversions.push_back(implicit_caster); + else pybind11_fail("implicitly_convertible: Unable to find type " + type_id()); - ((detail::type_info *) it->second)->implicit_conversions.push_back(implicit_caster); } template @@ -1590,11 +1586,8 @@ inline function get_type_overload(const void *this_ptr, const detail::type_info } template function get_overload(const T *this_ptr, const char *name) { - auto &cpp_types = detail::get_internals().registered_types_cpp; - auto it = cpp_types.find(typeid(T)); - if (it == cpp_types.end()) - return function(); - return get_type_overload(this_ptr, (const detail::type_info *) it->second, name); + auto tinfo = detail::get_type_info(typeid(T)); + return tinfo ? get_type_overload(this_ptr, tinfo, name) : function(); } #define PYBIND11_OVERLOAD_INT(ret_type, cname, name, ...) { \