Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:57

0001 /*
0002     tests/test_stl.cpp -- STL type casters
0003 
0004     Copyright (c) 2017 Wenzel Jakob <wenzel.jakob@epfl.ch>
0005 
0006     All rights reserved. Use of this source code is governed by a
0007     BSD-style license that can be found in the LICENSE file.
0008 */
0009 
0010 #include <pybind11/stl.h>
0011 
0012 #include "constructor_stats.h"
0013 #include "pybind11_tests.h"
0014 
0015 #ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
0016 #    define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
0017 #endif
0018 #include <pybind11/stl/filesystem.h>
0019 
0020 #include <string>
0021 #include <vector>
0022 
0023 #if defined(PYBIND11_TEST_BOOST)
0024 #    include <boost/optional.hpp>
0025 
0026 namespace PYBIND11_NAMESPACE {
0027 namespace detail {
0028 template <typename T>
0029 struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
0030 
0031 template <>
0032 struct type_caster<boost::none_t> : void_caster<boost::none_t> {};
0033 } // namespace detail
0034 } // namespace PYBIND11_NAMESPACE
0035 #endif
0036 
0037 // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
0038 #if defined(PYBIND11_HAS_VARIANT)
0039 using std::variant;
0040 #    define PYBIND11_TEST_VARIANT 1
0041 #elif defined(PYBIND11_TEST_BOOST)
0042 #    include <boost/variant.hpp>
0043 #    define PYBIND11_TEST_VARIANT 1
0044 using boost::variant;
0045 
0046 namespace PYBIND11_NAMESPACE {
0047 namespace detail {
0048 template <typename... Ts>
0049 struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
0050 
0051 template <>
0052 struct visit_helper<boost::variant> {
0053     template <typename... Args>
0054     static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
0055         return boost::apply_visitor(args...);
0056     }
0057 };
0058 } // namespace detail
0059 } // namespace PYBIND11_NAMESPACE
0060 #endif
0061 
0062 PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
0063 
0064 /// Issue #528: templated constructor
0065 struct TplCtorClass {
0066     template <typename T>
0067     explicit TplCtorClass(const T &) {}
0068     bool operator==(const TplCtorClass &) const { return true; }
0069 };
0070 
0071 namespace std {
0072 template <>
0073 struct hash<TplCtorClass> {
0074     size_t operator()(const TplCtorClass &) const { return 0; }
0075 };
0076 } // namespace std
0077 
0078 template <template <typename> class OptionalImpl, typename T>
0079 struct OptionalHolder {
0080     // NOLINTNEXTLINE(modernize-use-equals-default): breaks GCC 4.8
0081     OptionalHolder(){};
0082     bool member_initialized() const { return member && member->initialized; }
0083     OptionalImpl<T> member = T{};
0084 };
0085 
0086 enum class EnumType {
0087     kSet = 42,
0088     kUnset = 85,
0089 };
0090 
0091 // This is used to test that return-by-ref and return-by-copy policies are
0092 // handled properly for optional types. This is a regression test for a dangling
0093 // reference issue. The issue seemed to require the enum value type to
0094 // reproduce - it didn't seem to happen if the value type is just an integer.
0095 template <template <typename> class OptionalImpl>
0096 class OptionalProperties {
0097 public:
0098     using OptionalEnumValue = OptionalImpl<EnumType>;
0099 
0100     OptionalProperties() : value(EnumType::kSet) {}
0101     ~OptionalProperties() {
0102         // Reset value to detect use-after-destruction.
0103         // This is set to a specific value rather than nullopt to ensure that
0104         // the memory that contains the value gets re-written.
0105         value = EnumType::kUnset;
0106     }
0107 
0108     OptionalEnumValue &access_by_ref() { return value; }
0109     OptionalEnumValue access_by_copy() { return value; }
0110 
0111 private:
0112     OptionalEnumValue value;
0113 };
0114 
0115 // This type mimics aspects of boost::optional from old versions of Boost,
0116 // which exposed a dangling reference bug in Pybind11. Recent versions of
0117 // boost::optional, as well as libstdc++'s std::optional, don't seem to be
0118 // affected by the same issue. This is meant to be a minimal implementation
0119 // required to reproduce the issue, not fully standard-compliant.
0120 // See issue #3330 for more details.
0121 template <typename T>
0122 class ReferenceSensitiveOptional {
0123 public:
0124     using value_type = T;
0125 
0126     ReferenceSensitiveOptional() = default;
0127     // NOLINTNEXTLINE(google-explicit-constructor)
0128     ReferenceSensitiveOptional(const T &value) : storage{value} {}
0129     // NOLINTNEXTLINE(google-explicit-constructor)
0130     ReferenceSensitiveOptional(T &&value) : storage{std::move(value)} {}
0131     ReferenceSensitiveOptional &operator=(const T &value) {
0132         storage = {value};
0133         return *this;
0134     }
0135     ReferenceSensitiveOptional &operator=(T &&value) {
0136         storage = {std::move(value)};
0137         return *this;
0138     }
0139 
0140     template <typename... Args>
0141     T &emplace(Args &&...args) {
0142         storage.clear();
0143         storage.emplace_back(std::forward<Args>(args)...);
0144         return storage.back();
0145     }
0146 
0147     const T &value() const noexcept {
0148         assert(!storage.empty());
0149         return storage[0];
0150     }
0151 
0152     const T &operator*() const noexcept { return value(); }
0153 
0154     const T *operator->() const noexcept { return &value(); }
0155 
0156     explicit operator bool() const noexcept { return !storage.empty(); }
0157 
0158 private:
0159     std::vector<T> storage;
0160 };
0161 
0162 namespace PYBIND11_NAMESPACE {
0163 namespace detail {
0164 template <typename T>
0165 struct type_caster<ReferenceSensitiveOptional<T>>
0166     : optional_caster<ReferenceSensitiveOptional<T>> {};
0167 } // namespace detail
0168 } // namespace PYBIND11_NAMESPACE
0169 
0170 TEST_SUBMODULE(stl, m) {
0171     // test_vector
0172     m.def("cast_vector", []() { return std::vector<int>{1}; });
0173     m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
0174     // `std::vector<bool>` is special because it returns proxy objects instead of references
0175     m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; });
0176     m.def("load_bool_vector",
0177           [](const std::vector<bool> &v) { return v.at(0) == true && v.at(1) == false; });
0178     // Unnumbered regression (caused by #936): pointers to stl containers aren't castable
0179     m.def(
0180         "cast_ptr_vector",
0181         []() {
0182             // Using no-destructor idiom to side-step warnings from overzealous compilers.
0183             static auto *v = new std::vector<RValueCaster>{2};
0184             return v;
0185         },
0186         py::return_value_policy::reference);
0187 
0188     // test_deque
0189     m.def("cast_deque", []() { return std::deque<int>{1}; });
0190     m.def("load_deque", [](const std::deque<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
0191 
0192     // test_array
0193     m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
0194     m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
0195 
0196     // test_valarray
0197     m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
0198     m.def("load_valarray", [](const std::valarray<int> &v) {
0199         return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
0200     });
0201 
0202     // test_map
0203     m.def("cast_map", []() { return std::map<std::string, std::string>{{"key", "value"}}; });
0204     m.def("load_map", [](const std::map<std::string, std::string> &map) {
0205         return map.at("key") == "value" && map.at("key2") == "value2";
0206     });
0207 
0208     // test_set
0209     m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
0210     m.def("load_set", [](const std::set<std::string> &set) {
0211         return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
0212     });
0213 
0214     // test_recursive_casting
0215     m.def("cast_rv_vector", []() { return std::vector<RValueCaster>{2}; });
0216     m.def("cast_rv_array", []() { return std::array<RValueCaster, 3>(); });
0217     // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`),
0218     // casters don't typically do anything with that, which means they fall to the `const Type &`
0219     // caster.
0220     m.def("cast_rv_map", []() {
0221         return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}};
0222     });
0223     m.def("cast_rv_nested", []() {
0224         std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v;
0225         v.emplace_back();           // add an array
0226         v.back()[0].emplace_back(); // add a map to the array
0227         v.back()[0].back().emplace("b", RValueCaster{});
0228         v.back()[0].back().emplace("c", RValueCaster{});
0229         v.back()[1].emplace_back(); // add a map to the array
0230         v.back()[1].back().emplace("a", RValueCaster{});
0231         return v;
0232     });
0233     static std::array<RValueCaster, 2> lva;
0234     static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}},
0235                                                              {"b", RValueCaster{}}};
0236     static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>>
0237         lvn;
0238     lvn["a"].emplace_back();        // add a list
0239     lvn["a"].back().emplace_back(); // add an array
0240     lvn["a"].emplace_back();        // another list
0241     lvn["a"].back().emplace_back(); // add an array
0242     lvn["b"].emplace_back();        // add a list
0243     lvn["b"].back().emplace_back(); // add an array
0244     lvn["b"].back().emplace_back(); // add another array
0245     static std::vector<RValueCaster> lvv{2};
0246     m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; });
0247     m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; });
0248     m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; });
0249     m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; });
0250     // #853:
0251     m.def("cast_unique_ptr_vector", []() {
0252         std::vector<std::unique_ptr<UserType>> v;
0253         v.emplace_back(new UserType{7});
0254         v.emplace_back(new UserType{42});
0255         return v;
0256     });
0257 
0258     pybind11::enum_<EnumType>(m, "EnumType")
0259         .value("kSet", EnumType::kSet)
0260         .value("kUnset", EnumType::kUnset);
0261 
0262     // test_move_out_container
0263     struct MoveOutContainer {
0264         struct Value {
0265             int value;
0266         };
0267         std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
0268     };
0269     py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
0270         .def_readonly("value", &MoveOutContainer::Value::value);
0271     py::class_<MoveOutContainer>(m, "MoveOutContainer")
0272         .def(py::init<>())
0273         .def_property_readonly("move_list", &MoveOutContainer::move_list);
0274 
0275     // Class that can be move- and copy-constructed, but not assigned
0276     struct NoAssign {
0277         int value;
0278 
0279         explicit NoAssign(int value = 0) : value(value) {}
0280         NoAssign(const NoAssign &) = default;
0281         NoAssign(NoAssign &&) = default;
0282 
0283         NoAssign &operator=(const NoAssign &) = delete;
0284         NoAssign &operator=(NoAssign &&) = delete;
0285     };
0286     py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators")
0287         .def(py::init<>())
0288         .def(py::init<int>());
0289 
0290     struct MoveOutDetector {
0291         MoveOutDetector() = default;
0292         MoveOutDetector(const MoveOutDetector &) = default;
0293         MoveOutDetector(MoveOutDetector &&other) noexcept : initialized(other.initialized) {
0294             // steal underlying resource
0295             other.initialized = false;
0296         }
0297         bool initialized = true;
0298     };
0299     py::class_<MoveOutDetector>(m, "MoveOutDetector", "Class with move tracking")
0300         .def(py::init<>())
0301         .def_readonly("initialized", &MoveOutDetector::initialized);
0302 
0303 #ifdef PYBIND11_HAS_OPTIONAL
0304     // test_optional
0305     m.attr("has_optional") = true;
0306 
0307     using opt_int = std::optional<int>;
0308     using opt_no_assign = std::optional<NoAssign>;
0309     m.def("double_or_zero", [](const opt_int &x) -> int { return x.value_or(0) * 2; });
0310     m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); });
0311     m.def(
0312         "test_nullopt",
0313         [](opt_int x) { return x.value_or(42); },
0314         py::arg_v("x", std::nullopt, "None"));
0315     m.def(
0316         "test_no_assign",
0317         [](const opt_no_assign &x) { return x ? x->value : 42; },
0318         py::arg_v("x", std::nullopt, "None"));
0319 
0320     m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
0321     m.def("nodefer_none_optional", [](const py::none &) { return false; });
0322 
0323     using opt_holder = OptionalHolder<std::optional, MoveOutDetector>;
0324     py::class_<opt_holder>(m, "OptionalHolder", "Class with optional member")
0325         .def(py::init<>())
0326         .def_readonly("member", &opt_holder::member)
0327         .def("member_initialized", &opt_holder::member_initialized);
0328 
0329     using opt_props = OptionalProperties<std::optional>;
0330     pybind11::class_<opt_props>(m, "OptionalProperties")
0331         .def(pybind11::init<>())
0332         .def_property_readonly("access_by_ref", &opt_props::access_by_ref)
0333         .def_property_readonly("access_by_copy", &opt_props::access_by_copy);
0334 #endif
0335 
0336 #ifdef PYBIND11_HAS_EXP_OPTIONAL
0337     // test_exp_optional
0338     m.attr("has_exp_optional") = true;
0339 
0340     using exp_opt_int = std::experimental::optional<int>;
0341     using exp_opt_no_assign = std::experimental::optional<NoAssign>;
0342     m.def("double_or_zero_exp", [](const exp_opt_int &x) -> int { return x.value_or(0) * 2; });
0343     m.def("half_or_none_exp",
0344           [](int x) -> exp_opt_int { return x ? exp_opt_int(x / 2) : exp_opt_int(); });
0345     m.def(
0346         "test_nullopt_exp",
0347         [](exp_opt_int x) { return x.value_or(42); },
0348         py::arg_v("x", std::experimental::nullopt, "None"));
0349     m.def(
0350         "test_no_assign_exp",
0351         [](const exp_opt_no_assign &x) { return x ? x->value : 42; },
0352         py::arg_v("x", std::experimental::nullopt, "None"));
0353 
0354     using opt_exp_holder = OptionalHolder<std::experimental::optional, MoveOutDetector>;
0355     py::class_<opt_exp_holder>(m, "OptionalExpHolder", "Class with optional member")
0356         .def(py::init<>())
0357         .def_readonly("member", &opt_exp_holder::member)
0358         .def("member_initialized", &opt_exp_holder::member_initialized);
0359 
0360     using opt_exp_props = OptionalProperties<std::experimental::optional>;
0361     pybind11::class_<opt_exp_props>(m, "OptionalExpProperties")
0362         .def(pybind11::init<>())
0363         .def_property_readonly("access_by_ref", &opt_exp_props::access_by_ref)
0364         .def_property_readonly("access_by_copy", &opt_exp_props::access_by_copy);
0365 #endif
0366 
0367 #if defined(PYBIND11_TEST_BOOST)
0368     // test_boost_optional
0369     m.attr("has_boost_optional") = true;
0370 
0371     using boost_opt_int = boost::optional<int>;
0372     using boost_opt_no_assign = boost::optional<NoAssign>;
0373     m.def("double_or_zero_boost", [](const boost_opt_int &x) -> int { return x.value_or(0) * 2; });
0374     m.def("half_or_none_boost",
0375           [](int x) -> boost_opt_int { return x != 0 ? boost_opt_int(x / 2) : boost_opt_int(); });
0376     m.def(
0377         "test_nullopt_boost",
0378         [](boost_opt_int x) { return x.value_or(42); },
0379         py::arg_v("x", boost::none, "None"));
0380     m.def(
0381         "test_no_assign_boost",
0382         [](const boost_opt_no_assign &x) { return x ? x->value : 42; },
0383         py::arg_v("x", boost::none, "None"));
0384 
0385     using opt_boost_holder = OptionalHolder<boost::optional, MoveOutDetector>;
0386     py::class_<opt_boost_holder>(m, "OptionalBoostHolder", "Class with optional member")
0387         .def(py::init<>())
0388         .def_readonly("member", &opt_boost_holder::member)
0389         .def("member_initialized", &opt_boost_holder::member_initialized);
0390 
0391     using opt_boost_props = OptionalProperties<boost::optional>;
0392     pybind11::class_<opt_boost_props>(m, "OptionalBoostProperties")
0393         .def(pybind11::init<>())
0394         .def_property_readonly("access_by_ref", &opt_boost_props::access_by_ref)
0395         .def_property_readonly("access_by_copy", &opt_boost_props::access_by_copy);
0396 #endif
0397 
0398     // test_refsensitive_optional
0399     using refsensitive_opt_int = ReferenceSensitiveOptional<int>;
0400     using refsensitive_opt_no_assign = ReferenceSensitiveOptional<NoAssign>;
0401     m.def("double_or_zero_refsensitive",
0402           [](const refsensitive_opt_int &x) -> int { return (x ? x.value() : 0) * 2; });
0403     m.def("half_or_none_refsensitive", [](int x) -> refsensitive_opt_int {
0404         return x != 0 ? refsensitive_opt_int(x / 2) : refsensitive_opt_int();
0405     });
0406     m.def(
0407         "test_nullopt_refsensitive",
0408         // NOLINTNEXTLINE(performance-unnecessary-value-param)
0409         [](refsensitive_opt_int x) { return x ? x.value() : 42; },
0410         py::arg_v("x", refsensitive_opt_int(), "None"));
0411     m.def(
0412         "test_no_assign_refsensitive",
0413         [](const refsensitive_opt_no_assign &x) { return x ? x->value : 42; },
0414         py::arg_v("x", refsensitive_opt_no_assign(), "None"));
0415 
0416     using opt_refsensitive_holder = OptionalHolder<ReferenceSensitiveOptional, MoveOutDetector>;
0417     py::class_<opt_refsensitive_holder>(
0418         m, "OptionalRefSensitiveHolder", "Class with optional member")
0419         .def(py::init<>())
0420         .def_readonly("member", &opt_refsensitive_holder::member)
0421         .def("member_initialized", &opt_refsensitive_holder::member_initialized);
0422 
0423     using opt_refsensitive_props = OptionalProperties<ReferenceSensitiveOptional>;
0424     pybind11::class_<opt_refsensitive_props>(m, "OptionalRefSensitiveProperties")
0425         .def(pybind11::init<>())
0426         .def_property_readonly("access_by_ref", &opt_refsensitive_props::access_by_ref)
0427         .def_property_readonly("access_by_copy", &opt_refsensitive_props::access_by_copy);
0428 
0429 #ifdef PYBIND11_HAS_FILESYSTEM
0430     // test_fs_path
0431     m.attr("has_filesystem") = true;
0432     m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); });
0433 #endif
0434 
0435 #ifdef PYBIND11_TEST_VARIANT
0436     static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
0437                   "visitor::result_type is required by boost::variant in C++11 mode");
0438 
0439     struct visitor {
0440         using result_type = const char *;
0441 
0442         result_type operator()(int) { return "int"; }
0443         result_type operator()(const std::string &) { return "std::string"; }
0444         result_type operator()(double) { return "double"; }
0445         result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
0446 #    if defined(PYBIND11_HAS_VARIANT)
0447         result_type operator()(std::monostate) { return "std::monostate"; }
0448 #    endif
0449     };
0450 
0451     // test_variant
0452     m.def("load_variant", [](const variant<int, std::string, double, std::nullptr_t> &v) {
0453         return py::detail::visit_helper<variant>::call(visitor(), v);
0454     });
0455     m.def("load_variant_2pass", [](variant<double, int> v) {
0456         return py::detail::visit_helper<variant>::call(visitor(), v);
0457     });
0458     m.def("cast_variant", []() {
0459         using V = variant<int, std::string>;
0460         return py::make_tuple(V(5), V("Hello"));
0461     });
0462 
0463 #    if defined(PYBIND11_HAS_VARIANT)
0464     // std::monostate tests.
0465     m.def("load_monostate_variant",
0466           [](const variant<std::monostate, int, std::string> &v) -> const char * {
0467               return py::detail::visit_helper<variant>::call(visitor(), v);
0468           });
0469     m.def("cast_monostate_variant", []() {
0470         using V = variant<std::monostate, int, std::string>;
0471         return py::make_tuple(V{}, V(5), V("Hello"));
0472     });
0473 #    endif
0474 #endif
0475 
0476     // #528: templated constructor
0477     // (no python tests: the test here is that this compiles)
0478     m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
0479     m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
0480     m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
0481 #if defined(PYBIND11_HAS_OPTIONAL)
0482     m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
0483 #endif
0484 #if defined(PYBIND11_HAS_EXP_OPTIONAL)
0485     m.def("tpl_constr_optional_exp", [](std::experimental::optional<TplCtorClass> &) {});
0486 #endif
0487 #if defined(PYBIND11_TEST_BOOST)
0488     m.def("tpl_constr_optional_boost", [](boost::optional<TplCtorClass> &) {});
0489 #endif
0490 
0491     // test_vec_of_reference_wrapper
0492     // #171: Can't return STL structures containing reference wrapper
0493     m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) {
0494         static UserType p1{1}, p2{2}, p3{3};
0495         return std::vector<std::reference_wrapper<UserType>>{
0496             std::ref(p1), std::ref(p2), std::ref(p3), p4};
0497     });
0498 
0499     // test_stl_pass_by_pointer
0500     m.def(
0501         "stl_pass_by_pointer", [](std::vector<int> *v) { return *v; }, "v"_a = nullptr);
0502 
0503     // #1258: pybind11/stl.h converts string to vector<string>
0504     m.def("func_with_string_or_vector_string_arg_overload",
0505           [](const std::vector<std::string> &) { return 1; });
0506     m.def("func_with_string_or_vector_string_arg_overload",
0507           [](const std::list<std::string> &) { return 2; });
0508     m.def("func_with_string_or_vector_string_arg_overload", [](const std::string &) { return 3; });
0509 
0510     class Placeholder {
0511     public:
0512         Placeholder() { print_created(this); }
0513         Placeholder(const Placeholder &) = delete;
0514         ~Placeholder() { print_destroyed(this); }
0515     };
0516     py::class_<Placeholder>(m, "Placeholder");
0517 
0518     /// test_stl_vector_ownership
0519     m.def(
0520         "test_stl_ownership",
0521         []() {
0522             std::vector<Placeholder *> result;
0523             result.push_back(new Placeholder());
0524             return result;
0525         },
0526         py::return_value_policy::take_ownership);
0527 
0528     m.def("array_cast_sequence", [](std::array<int, 3> x) { return x; });
0529 
0530     /// test_issue_1561
0531     struct Issue1561Inner {
0532         std::string data;
0533     };
0534     struct Issue1561Outer {
0535         std::vector<Issue1561Inner> list;
0536     };
0537 
0538     py::class_<Issue1561Inner>(m, "Issue1561Inner")
0539         .def(py::init<std::string>())
0540         .def_readwrite("data", &Issue1561Inner::data);
0541 
0542     py::class_<Issue1561Outer>(m, "Issue1561Outer")
0543         .def(py::init<>())
0544         .def_readwrite("list", &Issue1561Outer::list);
0545 
0546     m.def(
0547         "return_vector_bool_raw_ptr",
0548         []() { return new std::vector<bool>(4513); },
0549         // Without explicitly specifying `take_ownership`, this function leaks.
0550         py::return_value_policy::take_ownership);
0551 }