112391Sjason@lowepower.com/* 212391Sjason@lowepower.com tests/test_factory_constructors.cpp -- tests construction from a factory function 312391Sjason@lowepower.com via py::init_factory() 412391Sjason@lowepower.com 512391Sjason@lowepower.com Copyright (c) 2017 Jason Rhinelander <jason@imaginary.ca> 612391Sjason@lowepower.com 712391Sjason@lowepower.com All rights reserved. Use of this source code is governed by a 812391Sjason@lowepower.com BSD-style license that can be found in the LICENSE file. 912391Sjason@lowepower.com*/ 1012391Sjason@lowepower.com 1112391Sjason@lowepower.com#include "pybind11_tests.h" 1212391Sjason@lowepower.com#include "constructor_stats.h" 1312391Sjason@lowepower.com#include <cmath> 1412391Sjason@lowepower.com 1512391Sjason@lowepower.com// Classes for testing python construction via C++ factory function: 1614299Sbbruce@ucdavis.edu// Not publicly constructible, copyable, or movable: 1712391Sjason@lowepower.comclass TestFactory1 { 1812391Sjason@lowepower.com friend class TestFactoryHelper; 1912391Sjason@lowepower.com TestFactory1() : value("(empty)") { print_default_created(this); } 2012391Sjason@lowepower.com TestFactory1(int v) : value(std::to_string(v)) { print_created(this, value); } 2112391Sjason@lowepower.com TestFactory1(std::string v) : value(std::move(v)) { print_created(this, value); } 2212391Sjason@lowepower.com TestFactory1(TestFactory1 &&) = delete; 2312391Sjason@lowepower.com TestFactory1(const TestFactory1 &) = delete; 2412391Sjason@lowepower.com TestFactory1 &operator=(TestFactory1 &&) = delete; 2512391Sjason@lowepower.com TestFactory1 &operator=(const TestFactory1 &) = delete; 2612391Sjason@lowepower.compublic: 2712391Sjason@lowepower.com std::string value; 2812391Sjason@lowepower.com ~TestFactory1() { print_destroyed(this); } 2912391Sjason@lowepower.com}; 3012391Sjason@lowepower.com// Non-public construction, but moveable: 3112391Sjason@lowepower.comclass TestFactory2 { 3212391Sjason@lowepower.com friend class TestFactoryHelper; 3312391Sjason@lowepower.com TestFactory2() : value("(empty2)") { print_default_created(this); } 3412391Sjason@lowepower.com TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } 3512391Sjason@lowepower.com TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } 3612391Sjason@lowepower.compublic: 3712391Sjason@lowepower.com TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } 3812391Sjason@lowepower.com TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } 3912391Sjason@lowepower.com std::string value; 4012391Sjason@lowepower.com ~TestFactory2() { print_destroyed(this); } 4112391Sjason@lowepower.com}; 4212391Sjason@lowepower.com// Mixed direct/factory construction: 4312391Sjason@lowepower.comclass TestFactory3 { 4412391Sjason@lowepower.comprotected: 4512391Sjason@lowepower.com friend class TestFactoryHelper; 4612391Sjason@lowepower.com TestFactory3() : value("(empty3)") { print_default_created(this); } 4712391Sjason@lowepower.com TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } 4812391Sjason@lowepower.compublic: 4912391Sjason@lowepower.com TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } 5012391Sjason@lowepower.com TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } 5112391Sjason@lowepower.com TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } 5212391Sjason@lowepower.com std::string value; 5312391Sjason@lowepower.com virtual ~TestFactory3() { print_destroyed(this); } 5412391Sjason@lowepower.com}; 5512391Sjason@lowepower.com// Inheritance test 5612391Sjason@lowepower.comclass TestFactory4 : public TestFactory3 { 5712391Sjason@lowepower.compublic: 5812391Sjason@lowepower.com TestFactory4() : TestFactory3() { print_default_created(this); } 5912391Sjason@lowepower.com TestFactory4(int v) : TestFactory3(v) { print_created(this, v); } 6012391Sjason@lowepower.com virtual ~TestFactory4() { print_destroyed(this); } 6112391Sjason@lowepower.com}; 6212391Sjason@lowepower.com// Another class for an invalid downcast test 6312391Sjason@lowepower.comclass TestFactory5 : public TestFactory3 { 6412391Sjason@lowepower.compublic: 6512391Sjason@lowepower.com TestFactory5(int i) : TestFactory3(i) { print_created(this, i); } 6612391Sjason@lowepower.com virtual ~TestFactory5() { print_destroyed(this); } 6712391Sjason@lowepower.com}; 6812391Sjason@lowepower.com 6912391Sjason@lowepower.comclass TestFactory6 { 7012391Sjason@lowepower.comprotected: 7112391Sjason@lowepower.com int value; 7212391Sjason@lowepower.com bool alias = false; 7312391Sjason@lowepower.compublic: 7412391Sjason@lowepower.com TestFactory6(int i) : value{i} { print_created(this, i); } 7512391Sjason@lowepower.com TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } 7612391Sjason@lowepower.com TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } 7712391Sjason@lowepower.com virtual ~TestFactory6() { print_destroyed(this); } 7812391Sjason@lowepower.com virtual int get() { return value; } 7912391Sjason@lowepower.com bool has_alias() { return alias; } 8012391Sjason@lowepower.com}; 8112391Sjason@lowepower.comclass PyTF6 : public TestFactory6 { 8212391Sjason@lowepower.compublic: 8312391Sjason@lowepower.com // Special constructor that allows the factory to construct a PyTF6 from a TestFactory6 only 8412391Sjason@lowepower.com // when an alias is needed: 8512391Sjason@lowepower.com PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } 8612391Sjason@lowepower.com PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } 8712391Sjason@lowepower.com PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } 8812391Sjason@lowepower.com PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } 8912391Sjason@lowepower.com PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } 9012391Sjason@lowepower.com virtual ~PyTF6() { print_destroyed(this); } 9112391Sjason@lowepower.com int get() override { PYBIND11_OVERLOAD(int, TestFactory6, get, /*no args*/); } 9212391Sjason@lowepower.com}; 9312391Sjason@lowepower.com 9412391Sjason@lowepower.comclass TestFactory7 { 9512391Sjason@lowepower.comprotected: 9612391Sjason@lowepower.com int value; 9712391Sjason@lowepower.com bool alias = false; 9812391Sjason@lowepower.compublic: 9912391Sjason@lowepower.com TestFactory7(int i) : value{i} { print_created(this, i); } 10012391Sjason@lowepower.com TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } 10112391Sjason@lowepower.com TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } 10212391Sjason@lowepower.com virtual ~TestFactory7() { print_destroyed(this); } 10312391Sjason@lowepower.com virtual int get() { return value; } 10412391Sjason@lowepower.com bool has_alias() { return alias; } 10512391Sjason@lowepower.com}; 10612391Sjason@lowepower.comclass PyTF7 : public TestFactory7 { 10712391Sjason@lowepower.compublic: 10812391Sjason@lowepower.com PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } 10912391Sjason@lowepower.com PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } 11012391Sjason@lowepower.com PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } 11112391Sjason@lowepower.com virtual ~PyTF7() { print_destroyed(this); } 11212391Sjason@lowepower.com int get() override { PYBIND11_OVERLOAD(int, TestFactory7, get, /*no args*/); } 11312391Sjason@lowepower.com}; 11412391Sjason@lowepower.com 11512391Sjason@lowepower.com 11612391Sjason@lowepower.comclass TestFactoryHelper { 11712391Sjason@lowepower.compublic: 11812391Sjason@lowepower.com // Non-movable, non-copyable type: 11912391Sjason@lowepower.com // Return via pointer: 12012391Sjason@lowepower.com static TestFactory1 *construct1() { return new TestFactory1(); } 12112391Sjason@lowepower.com // Holder: 12212391Sjason@lowepower.com static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); } 12312391Sjason@lowepower.com // pointer again 12412391Sjason@lowepower.com static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } 12512391Sjason@lowepower.com 12612391Sjason@lowepower.com // Moveable type: 12712391Sjason@lowepower.com // pointer: 12812391Sjason@lowepower.com static TestFactory2 *construct2() { return new TestFactory2(); } 12912391Sjason@lowepower.com // holder: 13012391Sjason@lowepower.com static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); } 13112391Sjason@lowepower.com // by value moving: 13212391Sjason@lowepower.com static TestFactory2 construct2(std::string a) { return TestFactory2(a); } 13312391Sjason@lowepower.com 13412391Sjason@lowepower.com // shared_ptr holder type: 13512391Sjason@lowepower.com // pointer: 13612391Sjason@lowepower.com static TestFactory3 *construct3() { return new TestFactory3(); } 13712391Sjason@lowepower.com // holder: 13812391Sjason@lowepower.com static std::shared_ptr<TestFactory3> construct3(int a) { return std::shared_ptr<TestFactory3>(new TestFactory3(a)); } 13912391Sjason@lowepower.com}; 14012391Sjason@lowepower.com 14112391Sjason@lowepower.comTEST_SUBMODULE(factory_constructors, m) { 14212391Sjason@lowepower.com 14312391Sjason@lowepower.com // Define various trivial types to allow simpler overload resolution: 14412391Sjason@lowepower.com py::module m_tag = m.def_submodule("tag"); 14512391Sjason@lowepower.com#define MAKE_TAG_TYPE(Name) \ 14612391Sjason@lowepower.com struct Name##_tag {}; \ 14712391Sjason@lowepower.com py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \ 14812391Sjason@lowepower.com m_tag.attr(#Name) = py::cast(Name##_tag{}) 14912391Sjason@lowepower.com MAKE_TAG_TYPE(pointer); 15012391Sjason@lowepower.com MAKE_TAG_TYPE(unique_ptr); 15112391Sjason@lowepower.com MAKE_TAG_TYPE(move); 15212391Sjason@lowepower.com MAKE_TAG_TYPE(shared_ptr); 15312391Sjason@lowepower.com MAKE_TAG_TYPE(derived); 15412391Sjason@lowepower.com MAKE_TAG_TYPE(TF4); 15512391Sjason@lowepower.com MAKE_TAG_TYPE(TF5); 15612391Sjason@lowepower.com MAKE_TAG_TYPE(null_ptr); 15712391Sjason@lowepower.com MAKE_TAG_TYPE(base); 15812391Sjason@lowepower.com MAKE_TAG_TYPE(invalid_base); 15912391Sjason@lowepower.com MAKE_TAG_TYPE(alias); 16012391Sjason@lowepower.com MAKE_TAG_TYPE(unaliasable); 16112391Sjason@lowepower.com MAKE_TAG_TYPE(mixed); 16212391Sjason@lowepower.com 16312391Sjason@lowepower.com // test_init_factory_basic, test_bad_type 16412391Sjason@lowepower.com py::class_<TestFactory1>(m, "TestFactory1") 16512391Sjason@lowepower.com .def(py::init([](unique_ptr_tag, int v) { return TestFactoryHelper::construct1(v); })) 16612391Sjason@lowepower.com .def(py::init(&TestFactoryHelper::construct1_string)) // raw function pointer 16712391Sjason@lowepower.com .def(py::init([](pointer_tag) { return TestFactoryHelper::construct1(); })) 16812391Sjason@lowepower.com .def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); })) 16912391Sjason@lowepower.com .def_readwrite("value", &TestFactory1::value) 17012391Sjason@lowepower.com ; 17112391Sjason@lowepower.com py::class_<TestFactory2>(m, "TestFactory2") 17212391Sjason@lowepower.com .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) 17312391Sjason@lowepower.com .def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) 17412391Sjason@lowepower.com .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) 17512391Sjason@lowepower.com .def_readwrite("value", &TestFactory2::value) 17612391Sjason@lowepower.com ; 17712391Sjason@lowepower.com 17812391Sjason@lowepower.com // Stateful & reused: 17912391Sjason@lowepower.com int c = 1; 18012391Sjason@lowepower.com auto c4a = [c](pointer_tag, TF4_tag, int a) { (void) c; return new TestFactory4(a);}; 18112391Sjason@lowepower.com 18212391Sjason@lowepower.com // test_init_factory_basic, test_init_factory_casting 18312391Sjason@lowepower.com py::class_<TestFactory3, std::shared_ptr<TestFactory3>>(m, "TestFactory3") 18412391Sjason@lowepower.com .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) 18512391Sjason@lowepower.com .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })) 18612391Sjason@lowepower.com .def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }) // placement-new ctor 18712391Sjason@lowepower.com 18812391Sjason@lowepower.com // factories returning a derived type: 18912391Sjason@lowepower.com .def(py::init(c4a)) // derived ptr 19012391Sjason@lowepower.com .def(py::init([](pointer_tag, TF5_tag, int a) { return new TestFactory5(a); })) 19112391Sjason@lowepower.com // derived shared ptr: 19212391Sjason@lowepower.com .def(py::init([](shared_ptr_tag, TF4_tag, int a) { return std::make_shared<TestFactory4>(a); })) 19312391Sjason@lowepower.com .def(py::init([](shared_ptr_tag, TF5_tag, int a) { return std::make_shared<TestFactory5>(a); })) 19412391Sjason@lowepower.com 19512391Sjason@lowepower.com // Returns nullptr: 19612391Sjason@lowepower.com .def(py::init([](null_ptr_tag) { return (TestFactory3 *) nullptr; })) 19712391Sjason@lowepower.com 19812391Sjason@lowepower.com .def_readwrite("value", &TestFactory3::value) 19912391Sjason@lowepower.com ; 20012391Sjason@lowepower.com 20112391Sjason@lowepower.com // test_init_factory_casting 20212391Sjason@lowepower.com py::class_<TestFactory4, TestFactory3, std::shared_ptr<TestFactory4>>(m, "TestFactory4") 20312391Sjason@lowepower.com .def(py::init(c4a)) // pointer 20412391Sjason@lowepower.com ; 20512391Sjason@lowepower.com 20612391Sjason@lowepower.com // Doesn't need to be registered, but registering makes getting ConstructorStats easier: 20712391Sjason@lowepower.com py::class_<TestFactory5, TestFactory3, std::shared_ptr<TestFactory5>>(m, "TestFactory5"); 20812391Sjason@lowepower.com 20912391Sjason@lowepower.com // test_init_factory_alias 21012391Sjason@lowepower.com // Alias testing 21112391Sjason@lowepower.com py::class_<TestFactory6, PyTF6>(m, "TestFactory6") 21212391Sjason@lowepower.com .def(py::init([](base_tag, int i) { return TestFactory6(i); })) 21312391Sjason@lowepower.com .def(py::init([](alias_tag, int i) { return PyTF6(i); })) 21412391Sjason@lowepower.com .def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) 21512391Sjason@lowepower.com .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) 21612391Sjason@lowepower.com .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) 21712391Sjason@lowepower.com .def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) 21812391Sjason@lowepower.com 21912391Sjason@lowepower.com .def("get", &TestFactory6::get) 22012391Sjason@lowepower.com .def("has_alias", &TestFactory6::has_alias) 22112391Sjason@lowepower.com 22212391Sjason@lowepower.com .def_static("get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference) 22312391Sjason@lowepower.com .def_static("get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference) 22412391Sjason@lowepower.com ; 22512391Sjason@lowepower.com 22612391Sjason@lowepower.com // test_init_factory_dual 22712391Sjason@lowepower.com // Separate alias constructor testing 22812391Sjason@lowepower.com py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7") 22912391Sjason@lowepower.com .def(py::init( 23012391Sjason@lowepower.com [](int i) { return TestFactory7(i); }, 23112391Sjason@lowepower.com [](int i) { return PyTF7(i); })) 23212391Sjason@lowepower.com .def(py::init( 23312391Sjason@lowepower.com [](pointer_tag, int i) { return new TestFactory7(i); }, 23412391Sjason@lowepower.com [](pointer_tag, int i) { return new PyTF7(i); })) 23512391Sjason@lowepower.com .def(py::init( 23612391Sjason@lowepower.com [](mixed_tag, int i) { return new TestFactory7(i); }, 23712391Sjason@lowepower.com [](mixed_tag, int i) { return PyTF7(i); })) 23812391Sjason@lowepower.com .def(py::init( 23912391Sjason@lowepower.com [](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, 24012391Sjason@lowepower.com [](mixed_tag, std::string s) { return new PyTF7((int) s.size()); })) 24112391Sjason@lowepower.com .def(py::init( 24212391Sjason@lowepower.com [](base_tag, pointer_tag, int i) { return new TestFactory7(i); }, 24312391Sjason@lowepower.com [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); })) 24412391Sjason@lowepower.com .def(py::init( 24512391Sjason@lowepower.com [](alias_tag, pointer_tag, int i) { return new PyTF7(i); }, 24612391Sjason@lowepower.com [](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); })) 24712391Sjason@lowepower.com .def(py::init( 24812391Sjason@lowepower.com [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); }, 24912391Sjason@lowepower.com [](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr<TestFactory7>(p); })) 25012391Sjason@lowepower.com .def(py::init( 25112391Sjason@lowepower.com [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); }, 25212391Sjason@lowepower.com [](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); })) // <-- invalid alias factory 25312391Sjason@lowepower.com 25412391Sjason@lowepower.com .def("get", &TestFactory7::get) 25512391Sjason@lowepower.com .def("has_alias", &TestFactory7::has_alias) 25612391Sjason@lowepower.com 25712391Sjason@lowepower.com .def_static("get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference) 25812391Sjason@lowepower.com .def_static("get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference) 25912391Sjason@lowepower.com ; 26012391Sjason@lowepower.com 26112391Sjason@lowepower.com // test_placement_new_alternative 26212391Sjason@lowepower.com // Class with a custom new operator but *without* a placement new operator (issue #948) 26312391Sjason@lowepower.com class NoPlacementNew { 26412391Sjason@lowepower.com public: 26512391Sjason@lowepower.com NoPlacementNew(int i) : i(i) { } 26612391Sjason@lowepower.com static void *operator new(std::size_t s) { 26712391Sjason@lowepower.com auto *p = ::operator new(s); 26812391Sjason@lowepower.com py::print("operator new called, returning", reinterpret_cast<uintptr_t>(p)); 26912391Sjason@lowepower.com return p; 27012391Sjason@lowepower.com } 27112391Sjason@lowepower.com static void operator delete(void *p) { 27212391Sjason@lowepower.com py::print("operator delete called on", reinterpret_cast<uintptr_t>(p)); 27312391Sjason@lowepower.com ::operator delete(p); 27412391Sjason@lowepower.com } 27512391Sjason@lowepower.com int i; 27612391Sjason@lowepower.com }; 27712391Sjason@lowepower.com // As of 2.2, `py::init<args>` no longer requires placement new 27812391Sjason@lowepower.com py::class_<NoPlacementNew>(m, "NoPlacementNew") 27912391Sjason@lowepower.com .def(py::init<int>()) 28012391Sjason@lowepower.com .def(py::init([]() { return new NoPlacementNew(100); })) 28112391Sjason@lowepower.com .def_readwrite("i", &NoPlacementNew::i) 28212391Sjason@lowepower.com ; 28312391Sjason@lowepower.com 28412391Sjason@lowepower.com 28512391Sjason@lowepower.com // test_reallocations 28612391Sjason@lowepower.com // Class that has verbose operator_new/operator_delete calls 28712391Sjason@lowepower.com struct NoisyAlloc { 28814299Sbbruce@ucdavis.edu NoisyAlloc(const NoisyAlloc &) = default; 28912391Sjason@lowepower.com NoisyAlloc(int i) { py::print(py::str("NoisyAlloc(int {})").format(i)); } 29012391Sjason@lowepower.com NoisyAlloc(double d) { py::print(py::str("NoisyAlloc(double {})").format(d)); } 29112391Sjason@lowepower.com ~NoisyAlloc() { py::print("~NoisyAlloc()"); } 29212391Sjason@lowepower.com 29312391Sjason@lowepower.com static void *operator new(size_t s) { py::print("noisy new"); return ::operator new(s); } 29412391Sjason@lowepower.com static void *operator new(size_t, void *p) { py::print("noisy placement new"); return p; } 29512391Sjason@lowepower.com static void operator delete(void *p, size_t) { py::print("noisy delete"); ::operator delete(p); } 29612391Sjason@lowepower.com static void operator delete(void *, void *) { py::print("noisy placement delete"); } 29712391Sjason@lowepower.com#if defined(_MSC_VER) && _MSC_VER < 1910 29812391Sjason@lowepower.com // MSVC 2015 bug: the above "noisy delete" isn't invoked (fixed in MSVC 2017) 29912391Sjason@lowepower.com static void operator delete(void *p) { py::print("noisy delete"); ::operator delete(p); } 30012391Sjason@lowepower.com#endif 30112391Sjason@lowepower.com }; 30212391Sjason@lowepower.com py::class_<NoisyAlloc>(m, "NoisyAlloc") 30312391Sjason@lowepower.com // Since these overloads have the same number of arguments, the dispatcher will try each of 30412391Sjason@lowepower.com // them until the arguments convert. Thus we can get a pre-allocation here when passing a 30512391Sjason@lowepower.com // single non-integer: 30612391Sjason@lowepower.com .def("__init__", [](NoisyAlloc *a, int i) { new (a) NoisyAlloc(i); }) // Regular constructor, runs first, requires preallocation 30712391Sjason@lowepower.com .def(py::init([](double d) { return new NoisyAlloc(d); })) 30812391Sjason@lowepower.com 30912391Sjason@lowepower.com // The two-argument version: first the factory pointer overload. 31012391Sjason@lowepower.com .def(py::init([](int i, int) { return new NoisyAlloc(i); })) 31112391Sjason@lowepower.com // Return-by-value: 31212391Sjason@lowepower.com .def(py::init([](double d, int) { return NoisyAlloc(d); })) 31312391Sjason@lowepower.com // Old-style placement new init; requires preallocation 31412391Sjason@lowepower.com .def("__init__", [](NoisyAlloc &a, double d, double) { new (&a) NoisyAlloc(d); }) 31512391Sjason@lowepower.com // Requires deallocation of previous overload preallocated value: 31612391Sjason@lowepower.com .def(py::init([](int i, double) { return new NoisyAlloc(i); })) 31712391Sjason@lowepower.com // Regular again: requires yet another preallocation 31812391Sjason@lowepower.com .def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }) 31912391Sjason@lowepower.com ; 32012391Sjason@lowepower.com 32112391Sjason@lowepower.com 32212391Sjason@lowepower.com 32312391Sjason@lowepower.com 32412391Sjason@lowepower.com // static_assert testing (the following def's should all fail with appropriate compilation errors): 32512391Sjason@lowepower.com#if 0 32612391Sjason@lowepower.com struct BadF1Base {}; 32712391Sjason@lowepower.com struct BadF1 : BadF1Base {}; 32812391Sjason@lowepower.com struct PyBadF1 : BadF1 {}; 32912391Sjason@lowepower.com py::class_<BadF1, PyBadF1, std::shared_ptr<BadF1>> bf1(m, "BadF1"); 33012391Sjason@lowepower.com // wrapped factory function must return a compatible pointer, holder, or value 33112391Sjason@lowepower.com bf1.def(py::init([]() { return 3; })); 33212391Sjason@lowepower.com // incompatible factory function pointer return type 33312391Sjason@lowepower.com bf1.def(py::init([]() { static int three = 3; return &three; })); 33412391Sjason@lowepower.com // incompatible factory function std::shared_ptr<T> return type: cannot convert shared_ptr<T> to holder 33512391Sjason@lowepower.com // (non-polymorphic base) 33612391Sjason@lowepower.com bf1.def(py::init([]() { return std::shared_ptr<BadF1Base>(new BadF1()); })); 33712391Sjason@lowepower.com#endif 33812391Sjason@lowepower.com} 339