@@ -2086,6 +2086,44 @@ declarations in generated :ref:`stubs <stubs>`,
2086
2086
Declares a callback that will be invoked when a C++ instance is first
2087
2087
cast into a Python object.
2088
2088
2089
+ .. cpp :struct :: upcast_hook
2090
+
2091
+ .. cpp :function :: upcast_hook(void * (* hook)(PyObject*, const std::type_info*) noexcept )
2092
+
2093
+ Allow Python instances of the class being bound to be passed to C++
2094
+ functions that expect a pointer to a subobject of that class.
2095
+ Since nanobind only acknowledges at most one base class of each bound type,
2096
+ the upcast hook can be helpful for providing some minimal emulation of
2097
+ additional bases.
2098
+
2099
+ The hook receives a nanobind instance as its first argument and the
2100
+ desired subobject type as its second. If it can make the cast, it
2101
+ returns a pointer to something of the requested type; if not, it
2102
+ returns nullptr.
2103
+
2104
+ **Example: **
2105
+
2106
+ .. code-block :: cpp
2107
+
2108
+ struct A { int a = 10; };
2109
+ struct B { int b = 20; };
2110
+ struct D : A, B { int d = 30; };
2111
+
2112
+ nb::class_<A>(m, "A").def_rw("a", &A::a);
2113
+ auto clsB = nb::class_<B>(m, "B").def_rw("b", &B::b);
2114
+
2115
+ auto try_D_to_B = [](PyObject *self_py, const std::type_info *target) noexcept -> void* {
2116
+ D *self = nb::inst_ptr<D>(self_py);
2117
+ if (*target == &typeid(B)) {
2118
+ return static_cast<B*>(self);
2119
+ }
2120
+ return nullptr;
2121
+ };
2122
+
2123
+ auto clsD = nb::class_<D, A>(m, "D", nb::upcast_hook(try_D_to_B))
2124
+ .def_rw("d", &D::d);
2125
+ clsD.attr("b") = clsB.attr("b");
2126
+
2089
2127
2090
2128
.. _enum_binding_annotations :
2091
2129
0 commit comments