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