#include #include #include "pybind11_tests.h" #include #include #include namespace test_class_sh_mi_thunks { // For general background: https://shaharmike.com/cpp/vtable-part2/ // C++ vtables - Part 2 - Multiple Inheritance // ... the compiler creates a 'thunk' method that corrects `this` ... struct Base0 { virtual ~Base0() = default; Base0() = default; Base0(const Base0 &) = delete; }; struct Base1 { virtual ~Base1() = default; // Using `vector` here because it is known to make this test very sensitive to bugs. std::vector vec = {1, 2, 3, 4, 5}; Base1() = default; Base1(const Base1 &) = delete; }; struct Derived : Base1, Base0 { ~Derived() override = default; Derived() = default; Derived(const Derived &) = delete; }; } // namespace test_class_sh_mi_thunks PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base0) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Base1) PYBIND11_SMART_HOLDER_TYPE_CASTERS(test_class_sh_mi_thunks::Derived) TEST_SUBMODULE(class_sh_mi_thunks, m) { using namespace test_class_sh_mi_thunks; m.def("ptrdiff_drvd_base0", []() { auto drvd = std::unique_ptr(new Derived); auto *base0 = dynamic_cast(drvd.get()); return std::ptrdiff_t(reinterpret_cast(drvd.get()) - reinterpret_cast(base0)); }); py::classh(m, "Base0"); py::classh(m, "Base1"); py::classh(m, "Derived"); m.def( "get_drvd_as_base0_raw_ptr", []() { auto *drvd = new Derived; auto *base0 = dynamic_cast(drvd); printf("\nLOOOK get raw drvd %ld\n", (long) drvd); fflush(stdout); // NOLINT printf("\nLOOOK get raw base %ld\n", (long) base0); fflush(stdout); // NOLINT return base0; }, py::return_value_policy::take_ownership); m.def("get_drvd_as_base0_shared_ptr", []() { auto drvd = std::make_shared(); auto base0 = std::dynamic_pointer_cast(drvd); printf("\nLOOOK get shd drvd %ld\n", (long) drvd.get()); fflush(stdout); // NOLINT printf("\nLOOOK get shd base %ld\n", (long) base0.get()); fflush(stdout); // NOLINT return base0; }); m.def("get_drvd_as_base0_unique_ptr", []() { auto drvd = std::unique_ptr(new Derived); auto base0 = std::unique_ptr(std::move(drvd)); return base0; }); m.def("vec_size_base0_raw_ptr", [](const Base0 *obj) { printf("\nLOOOK raw const Base0 *obj %ld\n", (long) obj); fflush(stdout); // NOLINT const auto *obj_der = dynamic_cast(obj); printf("\nLOOOK raw const auto *obj_der %ld\n", (long) obj_der); fflush(stdout); // NOLINT if (obj_der == nullptr) { return std::size_t(0); } return obj_der->vec.size(); }); m.def("vec_size_base0_shared_ptr", [](const std::shared_ptr &obj) -> std::size_t { printf("\nLOOOK shd const Base0 *obj %ld\n", (long) obj.get()); fflush(stdout); // NOLINT const auto obj_der = std::dynamic_pointer_cast(obj); printf("\nLOOOK shd const auto *obj_der %ld\n", (long) obj_der.get()); fflush(stdout); // NOLINT if (!obj_der) { return std::size_t(0); } return obj_der->vec.size(); }); m.def("vec_size_base0_unique_ptr", [](std::unique_ptr obj) -> std::size_t { const auto *obj_der = dynamic_cast(obj.get()); if (obj_der == nullptr) { return std::size_t(0); } return obj_der->vec.size(); }); }