431 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
		
		
			
		
	
	
			431 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
|  | /*
 | ||
|  |     tests/test_factory_constructors.cpp -- tests construction from a factory function | ||
|  |                                            via py::init_factory() | ||
|  | 
 | ||
|  |     Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca> | ||
|  | 
 | ||
|  |     All rights reserved. Use of this source code is governed by a | ||
|  |     BSD-style license that can be found in the LICENSE file. | ||
|  | */ | ||
|  | 
 | ||
|  | #include "constructor_stats.h"
 | ||
|  | #include "pybind11_tests.h"
 | ||
|  | 
 | ||
|  | #include <cmath>
 | ||
|  | #include <new>
 | ||
|  | #include <utility>
 | ||
|  | 
 | ||
|  | // Classes for testing python construction via C++ factory function:
 | ||
|  | // Not publicly constructible, copyable, or movable:
 | ||
|  | class TestFactory1 { | ||
|  |     friend class TestFactoryHelper; | ||
|  |     TestFactory1() : value("(empty)") { print_default_created(this); } | ||
|  |     explicit TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } | ||
|  |     explicit TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } | ||
|  | 
 | ||
|  | public: | ||
|  |     std::string value; | ||
|  |     TestFactory1(TestFactory1 &&) = delete; | ||
|  |     TestFactory1(const TestFactory1 &) = delete; | ||
|  |     TestFactory1 &operator=(TestFactory1 &&) = delete; | ||
|  |     TestFactory1 &operator=(const TestFactory1 &) = delete; | ||
|  |     ~TestFactory1() { print_destroyed(this); } | ||
|  | }; | ||
|  | // Non-public construction, but moveable:
 | ||
|  | class TestFactory2 { | ||
|  |     friend class TestFactoryHelper; | ||
|  |     TestFactory2() : value("(empty2)") { print_default_created(this); } | ||
|  |     explicit TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } | ||
|  |     explicit TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } | ||
|  | 
 | ||
|  | public: | ||
|  |     TestFactory2(TestFactory2 &&m) noexcept : value{std::move(m.value)} { | ||
|  |         print_move_created(this); | ||
|  |     } | ||
|  |     TestFactory2 &operator=(TestFactory2 &&m) noexcept { | ||
|  |         value = std::move(m.value); | ||
|  |         print_move_assigned(this); | ||
|  |         return *this; | ||
|  |     } | ||
|  |     std::string value; | ||
|  |     ~TestFactory2() { print_destroyed(this); } | ||
|  | }; | ||
|  | // Mixed direct/factory construction:
 | ||
|  | class TestFactory3 { | ||
|  | protected: | ||
|  |     friend class TestFactoryHelper; | ||
|  |     TestFactory3() : value("(empty3)") { print_default_created(this); } | ||
|  |     explicit TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } | ||
|  | 
 | ||
|  | public: | ||
|  |     explicit TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } | ||
|  |     TestFactory3(TestFactory3 &&m) noexcept : value{std::move(m.value)} { | ||
|  |         print_move_created(this); | ||
|  |     } | ||
|  |     TestFactory3 &operator=(TestFactory3 &&m) noexcept { | ||
|  |         value = std::move(m.value); | ||
|  |         print_move_assigned(this); | ||
|  |         return *this; | ||
|  |     } | ||
|  |     std::string value; | ||
|  |     virtual ~TestFactory3() { print_destroyed(this); } | ||
|  | }; | ||
|  | // Inheritance test
 | ||
|  | class TestFactory4 : public TestFactory3 { | ||
|  | public: | ||
|  |     TestFactory4() : TestFactory3() { print_default_created(this); } | ||
|  |     explicit TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } | ||
|  |     ~TestFactory4() override { print_destroyed(this); } | ||
|  | }; | ||
|  | // Another class for an invalid downcast test
 | ||
|  | class TestFactory5 : public TestFactory3 { | ||
|  | public: | ||
|  |     explicit TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } | ||
|  |     ~TestFactory5() override { print_destroyed(this); } | ||
|  | }; | ||
|  | 
 | ||
|  | class TestFactory6 { | ||
|  | protected: | ||
|  |     int value; | ||
|  |     bool alias = false; | ||
|  | 
 | ||
|  | public: | ||
|  |     explicit TestFactory6(int i) : value{i} { print_created(this, i); } | ||
|  |     TestFactory6(TestFactory6 &&f) noexcept { | ||
|  |         print_move_created(this); | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         value = f.value; | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         alias = f.alias; | ||
|  |     } | ||
|  |     TestFactory6(const TestFactory6 &f) { | ||
|  |         print_copy_created(this); | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         value = f.value; | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         alias = f.alias; | ||
|  |     } | ||
|  |     virtual ~TestFactory6() { print_destroyed(this); } | ||
|  |     virtual int get() { return value; } | ||
|  |     bool has_alias() const { return alias; } | ||
|  | }; | ||
|  | class PyTF6 : public TestFactory6 { | ||
|  | public: | ||
|  |     // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only
 | ||
|  |     // when an alias is needed:
 | ||
|  |     explicit PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { | ||
|  |         alias = true; | ||
|  |         print_created(this, "move", value); | ||
|  |     } | ||
|  |     explicit PyTF6(int i) : TestFactory6(i) { | ||
|  |         alias = true; | ||
|  |         print_created(this, i); | ||
|  |     } | ||
|  |     PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); } | ||
|  |     PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } | ||
|  |     explicit PyTF6(std::string s) : TestFactory6((int) s.size()) { | ||
|  |         alias = true; | ||
|  |         print_created(this, s); | ||
|  |     } | ||
|  |     ~PyTF6() override { print_destroyed(this); } | ||
|  |     int get() override { PYBIND11_OVERRIDE(int, TestFactory6, get, /*no args*/); } | ||
|  | }; | ||
|  | 
 | ||
|  | class TestFactory7 { | ||
|  | protected: | ||
|  |     int value; | ||
|  |     bool alias = false; | ||
|  | 
 | ||
|  | public: | ||
|  |     explicit TestFactory7(int i) : value{i} { print_created(this, i); } | ||
|  |     TestFactory7(TestFactory7 &&f) noexcept { | ||
|  |         print_move_created(this); | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         value = f.value; | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         alias = f.alias; | ||
|  |     } | ||
|  |     TestFactory7(const TestFactory7 &f) { | ||
|  |         print_copy_created(this); | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         value = f.value; | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         alias = f.alias; | ||
|  |     } | ||
|  |     virtual ~TestFactory7() { print_destroyed(this); } | ||
|  |     virtual int get() { return value; } | ||
|  |     bool has_alias() const { return alias; } | ||
|  | }; | ||
|  | class PyTF7 : public TestFactory7 { | ||
|  | public: | ||
|  |     explicit PyTF7(int i) : TestFactory7(i) { | ||
|  |         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
 | ||
|  |         alias = true; | ||
|  |         print_created(this, i); | ||
|  |     } | ||
|  |     PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); } | ||
|  |     PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } | ||
|  |     ~PyTF7() override { print_destroyed(this); } | ||
|  |     int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); } | ||
|  | }; | ||
|  | 
 | ||
|  | class TestFactoryHelper { | ||
|  | public: | ||
|  |     // Non-movable, non-copyable type:
 | ||
|  |     // Return via pointer:
 | ||
|  |     static TestFactory1 *construct1() { return new TestFactory1(); } | ||
|  |     // Holder:
 | ||
|  |     static std::unique_ptr<TestFactory1> construct1(int a) { | ||
|  |         return std::unique_ptr<TestFactory1>(new TestFactory1(a)); | ||
|  |     } | ||
|  |     // pointer again
 | ||
|  |     static TestFactory1 *construct1_string(std::string a) { | ||
|  |         return new TestFactory1(std::move(a)); | ||
|  |     } | ||
|  | 
 | ||
|  |     // Moveable type:
 | ||
|  |     // pointer:
 | ||
|  |     static TestFactory2 *construct2() { return new TestFactory2(); } | ||
|  |     // holder:
 | ||
|  |     static std::unique_ptr<TestFactory2> construct2(int a) { | ||
|  |         return std::unique_ptr<TestFactory2>(new TestFactory2(a)); | ||
|  |     } | ||
|  |     // by value moving:
 | ||
|  |     static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); } | ||
|  | 
 | ||
|  |     // shared_ptr holder type:
 | ||
|  |     // pointer:
 | ||
|  |     static TestFactory3 *construct3() { return new TestFactory3(); } | ||
|  |     // holder:
 | ||
|  |     static std::shared_ptr<TestFactory3> construct3(int a) { | ||
|  |         return std::shared_ptr<TestFactory3>(new TestFactory3(a)); | ||
|  |     } | ||
|  | }; | ||
|  | 
 | ||
|  | TEST_SUBMODULE(factory_constructors, m) { | ||
|  | 
 | ||
|  |     // Define various trivial types to allow simpler overload resolution:
 | ||
|  |     py::module_ m_tag = m.def_submodule("tag"); | ||
|  | #define MAKE_TAG_TYPE(Name)                                                                       \
 | ||
|  |     struct Name##_tag {};                                                                         \ | ||
|  |     py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>());                                \ | ||
|  |     m_tag.attr(#Name) = py::cast(Name##_tag{}) | ||
|  |     MAKE_TAG_TYPE(pointer); | ||
|  |     MAKE_TAG_TYPE(unique_ptr); | ||
|  |     MAKE_TAG_TYPE(move); | ||
|  |     MAKE_TAG_TYPE(shared_ptr); | ||
|  |     MAKE_TAG_TYPE(derived); | ||
|  |     MAKE_TAG_TYPE(TF4); | ||
|  |     MAKE_TAG_TYPE(TF5); | ||
|  |     MAKE_TAG_TYPE(null_ptr); | ||
|  |     MAKE_TAG_TYPE(null_unique_ptr); | ||
|  |     MAKE_TAG_TYPE(null_shared_ptr); | ||
|  |     MAKE_TAG_TYPE(base); | ||
|  |     MAKE_TAG_TYPE(invalid_base); | ||
|  |     MAKE_TAG_TYPE(alias); | ||
|  |     MAKE_TAG_TYPE(unaliasable); | ||
|  |     MAKE_TAG_TYPE(mixed); | ||
|  | 
 | ||
|  |     // test_init_factory_basic, test_bad_type
 | ||
|  |     py::class_<TestFactory1>(m, "TestFactory1") | ||
|  |         .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) | ||
|  |         .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer
 | ||
|  |         .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) | ||
|  |         .def(py::init( | ||
|  |             [](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) | ||
|  |         .def_readwrite("value", &TestFactory1::value); | ||
|  |     py::class_<TestFactory2>(m, "TestFactory2") | ||
|  |         .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) | ||
|  |         .def(py::init([](unique_ptr_tag, std::string v) { | ||
|  |             return TestFactoryHelper::construct2(std::move(v)); | ||
|  |         })) | ||
|  |         .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) | ||
|  |         .def_readwrite("value", &TestFactory2::value); | ||
|  | 
 | ||
|  |     // Stateful & reused:
 | ||
|  |     int c = 1; | ||
|  |     auto c4a = [c](pointer_tag, TF4_tag, int a) { | ||
|  |         (void) c; | ||
|  |         return new TestFactory4(a); | ||
|  |     }; | ||
|  | 
 | ||
|  |     // test_init_factory_basic, test_init_factory_casting
 | ||
|  |     py::class_<TestFactory3, std::shared_ptr<TestFactory3>> pyTestFactory3(m, "TestFactory3"); | ||
|  |     pyTestFactory3 | ||
|  |         .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) | ||
|  |         .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })); | ||
|  |     ignoreOldStyleInitWarnings([&pyTestFactory3]() { | ||
|  |         pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) { | ||
|  |             new (&self) TestFactory3(std::move(v)); | ||
|  |         }); // placement-new ctor
 | ||
|  |     }); | ||
|  |     pyTestFactory3 | ||
|  |         // factories returning a derived type:
 | ||
|  |         .def(py::init(c4a)) // derived ptr
 | ||
|  |         .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) | ||
|  |         // derived shared ptr:
 | ||
|  |         .def(py::init( | ||
|  |             [](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); })) | ||
|  |         .def(py::init( | ||
|  |             [](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); })) | ||
|  | 
 | ||
|  |         // Returns nullptr:
 | ||
|  |         .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) | ||
|  |         .def(py::init([](null_unique_ptr_tag) { return std::unique_ptr<TestFactory3>(); })) | ||
|  |         .def(py::init([](null_shared_ptr_tag) { return std::shared_ptr<TestFactory3>(); })) | ||
|  | 
 | ||
|  |         .def_readwrite("value", &TestFactory3::value); | ||
|  | 
 | ||
|  |     // test_init_factory_casting
 | ||
|  |     py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4") | ||
|  |         .def(py::init(c4a)) // pointer
 | ||
|  |         ; | ||
|  | 
 | ||
|  |     // Doesn't need to be registered, but registering makes getting ConstructorStats easier:
 | ||
|  |     py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5"); | ||
|  | 
 | ||
|  |     // test_init_factory_alias
 | ||
|  |     // Alias testing
 | ||
|  |     py::class_<TestFactory6, PyTF6>(m, "TestFactory6") | ||
|  |         .def(py::init([](base_tag, int i) { return TestFactory6(i); })) | ||
|  |         .def(py::init([](alias_tag, int i) { return PyTF6(i); })) | ||
|  |         .def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); })) | ||
|  |         .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) | ||
|  |         .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) | ||
|  |         .def(py::init( | ||
|  |             [](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) | ||
|  | 
 | ||
|  |         .def("get", &TestFactory6::get) | ||
|  |         .def("has_alias", &TestFactory6::has_alias) | ||
|  | 
 | ||
|  |         .def_static( | ||
|  |             "get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference) | ||
|  |         .def_static( | ||
|  |             "get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference); | ||
|  | 
 | ||
|  |     // test_init_factory_dual
 | ||
|  |     // Separate alias constructor testing
 | ||
|  |     py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7") | ||
|  |         .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); })) | ||
|  |         .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); }, | ||
|  |                       [](pointer_tag, int i) { return new PyTF7(i); })) | ||
|  |         .def(py::init([](mixed_tag, int i) { return new TestFactory7(i); }, | ||
|  |                       [](mixed_tag, int i) { return PyTF7(i); })) | ||
|  |         .def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); }, | ||
|  |                       [](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); })) | ||
|  |         .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, | ||
|  |                       [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) | ||
|  |         .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, | ||
|  |                       [](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); })) | ||
|  |         .def(py::init( | ||
|  |             [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); }, | ||
|  |             [](shared_ptr_tag, base_tag, int i) { | ||
|  |                 auto *p = new PyTF7(i); | ||
|  |                 return std::shared_ptr<TestFactory7>(p); | ||
|  |             })) | ||
|  |         .def(py::init([](shared_ptr_tag, | ||
|  |                          invalid_base_tag, | ||
|  |                          int i) { return std::make_shared<TestFactory7>(i); }, | ||
|  |                       [](shared_ptr_tag, invalid_base_tag, int i) { | ||
|  |                           return std::make_shared<TestFactory7>(i); | ||
|  |                       })) // <-- invalid alias factory
 | ||
|  | 
 | ||
|  |         .def("get", &TestFactory7::get) | ||
|  |         .def("has_alias", &TestFactory7::has_alias) | ||
|  | 
 | ||
|  |         .def_static( | ||
|  |             "get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference) | ||
|  |         .def_static( | ||
|  |             "get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference); | ||
|  | 
 | ||
|  |     // test_placement_new_alternative
 | ||
|  |     // Class with a custom new operator but *without* a placement new operator (issue #948)
 | ||
|  |     class NoPlacementNew { | ||
|  |     public: | ||
|  |         explicit NoPlacementNew(int i) : i(i) {} | ||
|  |         static void *operator new(std::size_t s) { | ||
|  |             auto *p = ::operator new(s); | ||
|  |             py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p)); | ||
|  |             return p; | ||
|  |         } | ||
|  |         static void operator delete(void *p) { | ||
|  |             py::print("operator delete called on", reinterpret_cast<uintptr_t>(p)); | ||
|  |             ::operator delete(p); | ||
|  |         } | ||
|  |         int i; | ||
|  |     }; | ||
|  |     // As of 2.2, `py::init<args>` no longer requires placement new
 | ||
|  |     py::class_<NoPlacementNew>(m, "NoPlacementNew") | ||
|  |         .def(py::init<int>()) | ||
|  |         .def(py::init([]() { return new NoPlacementNew(100); })) | ||
|  |         .def_readwrite("i", &NoPlacementNew::i); | ||
|  | 
 | ||
|  |     // test_reallocations
 | ||
|  |     // Class that has verbose operator_new/operator_delete calls
 | ||
|  |     struct NoisyAlloc { | ||
|  |         NoisyAlloc(const NoisyAlloc &) = default; | ||
|  |         explicit NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } | ||
|  |         explicit NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } | ||
|  |         ~NoisyAlloc() { py::print("~NoisyAlloc()"); } | ||
|  | 
 | ||
|  |         static void *operator new(size_t s) { | ||
|  |             py::print("noisy new"); | ||
|  |             return ::operator new(s); | ||
|  |         } | ||
|  |         static void *operator new(size_t, void *p) { | ||
|  |             py::print("noisy placement new"); | ||
|  |             return p; | ||
|  |         } | ||
|  |         static void operator delete(void *p, size_t) { | ||
|  |             py::print("noisy delete"); | ||
|  |             ::operator delete(p); | ||
|  |         } | ||
|  |         static void operator delete(void *, void *) { py::print("noisy placement delete"); } | ||
|  |     }; | ||
|  | 
 | ||
|  |     py::class_<NoisyAlloc> pyNoisyAlloc(m, "NoisyAlloc"); | ||
|  |     // Since these overloads have the same number of arguments, the dispatcher will try each of
 | ||
|  |     // them until the arguments convert.  Thus we can get a pre-allocation here when passing a
 | ||
|  |     // single non-integer:
 | ||
|  |     ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { | ||
|  |         pyNoisyAlloc.def("__init__", [](NoisyAlloc *a, int i) { | ||
|  |             new (a) NoisyAlloc(i); | ||
|  |         }); // Regular constructor, runs first, requires preallocation
 | ||
|  |     }); | ||
|  | 
 | ||
|  |     pyNoisyAlloc.def(py::init([](double d) { return new NoisyAlloc(d); })); | ||
|  | 
 | ||
|  |     // The two-argument version: first the factory pointer overload.
 | ||
|  |     pyNoisyAlloc.def(py::init([](int i, int) { return new NoisyAlloc(i); })); | ||
|  |     // Return-by-value:
 | ||
|  |     pyNoisyAlloc.def(py::init([](double d, int) { return NoisyAlloc(d); })); | ||
|  |     // Old-style placement new init; requires preallocation
 | ||
|  |     ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { | ||
|  |         pyNoisyAlloc.def("__init__", | ||
|  |                          [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }); | ||
|  |     }); | ||
|  |     // Requires deallocation of previous overload preallocated value:
 | ||
|  |     pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); })); | ||
|  |     // Regular again: requires yet another preallocation
 | ||
|  |     ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { | ||
|  |         pyNoisyAlloc.def( | ||
|  |             "__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); }); | ||
|  |     }); | ||
|  | 
 | ||
|  |     // static_assert testing (the following def's should all fail with appropriate compilation
 | ||
|  |     // errors):
 | ||
|  | #if 0
 | ||
|  |     struct BadF1Base {}; | ||
|  |     struct BadF1 : BadF1Base {}; | ||
|  |     struct PyBadF1 : BadF1 {}; | ||
|  |     py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1"); | ||
|  |     // wrapped factory function must return a compatible pointer, holder, or value
 | ||
|  |     bf1.def(py::init([]() { return 3; })); | ||
|  |     // incompatible factory function pointer return type
 | ||
|  |     bf1.def(py::init([]() { static int three = 3; return &three; })); | ||
|  |     // incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder
 | ||
|  |     // (non-polymorphic base)
 | ||
|  |     bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); })); | ||
|  | #endif
 | ||
|  | } |