issues.cpp 6.56 KB
Newer Older
1
2
3
/*
    example/issues.cpp -- collection of testcases for miscellaneous issues

4
    Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5
6
7
8
9
10

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#include "example.h"
11
#include <pybind11/stl.h>
12
#include <pybind11/operators.h>
13

Wenzel Jakob's avatar
Wenzel Jakob committed
14
15
PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>);

16
17
18
void init_issues(py::module &m) {
    py::module m2 = m.def_submodule("issues");

Wenzel Jakob's avatar
Wenzel Jakob committed
19
20
21
22
23
24
#if !defined(_MSC_VER)
    // Visual Studio 2015 currently cannot compile this test
    // (see the comment in type_caster_base::make_copy_constructor)
    // #70 compilation issue if operator new is not public
    class NonConstructible { private: void *operator new(size_t bytes) throw(); };
    py::class_<NonConstructible>(m, "Foo");
25
    m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
Wenzel Jakob's avatar
Wenzel Jakob committed
26
27
28
        py::return_value_policy::reference);
#endif

29
30
    // #137: const char* isn't handled properly
    m2.def("print_cchar", [](const char *string) { std::cout << string << std::endl; });
31
32
33

    // #150: char bindings broken
    m2.def("print_char", [](char c) { std::cout << c << std::endl; });
34
35

    // #159: virtual function dispatch has problems with similar-named functions
Wenzel Jakob's avatar
Wenzel Jakob committed
36
37
38
    struct Base { virtual void dispatch(void) const {
        /* for some reason MSVC2015 can't compile this if the function is pure virtual */
    }; };
Wenzel Jakob's avatar
Wenzel Jakob committed
39
40
41
42
43
44
45

    struct DispatchIssue : Base {
        virtual void dispatch(void) const {
            PYBIND11_OVERLOAD_PURE(void, Base, dispatch, /* no arguments */);
        }
    };

46
    py::class_<Base, std::unique_ptr<Base>, DispatchIssue>(m2, "DispatchIssue")
47
        .def(py::init<>())
48
49
        .def("dispatch", &Base::dispatch);

Wenzel Jakob's avatar
Wenzel Jakob committed
50
51
52
    m2.def("dispatch_issue_go", [](const Base * b) { b->dispatch(); });

    struct Placeholder { int i; Placeholder(int i) : i(i) { } };
53
54

    py::class_<Placeholder>(m2, "Placeholder")
55
        .def(py::init<int>())
56
57
58
        .def("__repr__", [](const Placeholder &p) { return "Placeholder[" + std::to_string(p.i) + "]"; });

    // #171: Can't return reference wrappers (or STL datastructures containing them)
59
    m2.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<Placeholder> p4){
60
61
        Placeholder *p1 = new Placeholder{1};
        Placeholder *p2 = new Placeholder{2};
62
        Placeholder *p3 = new Placeholder{3};
63
64
65
66
        std::vector<std::reference_wrapper<Placeholder>> v;
        v.push_back(std::ref(*p1));
        v.push_back(std::ref(*p2));
        v.push_back(std::ref(*p3));
67
        v.push_back(p4);
68
69
        return v;
    });
70
71
72
73
74

    // #181: iterator passthrough did not compile
    m2.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
        return py::make_iterator(std::begin(s), std::end(s));
    });
Wenzel Jakob's avatar
Wenzel Jakob committed
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103

    // #187: issue involving std::shared_ptr<> return value policy & garbage collection
    struct ElementBase { virtual void foo() { } /* Force creation of virtual table */ };
    struct ElementA : ElementBase {
        ElementA(int v) : v(v) { }
        int value() { return v; }
        int v;
    };

    struct ElementList {
        void add(std::shared_ptr<ElementBase> e) { l.push_back(e); }
        std::vector<std::shared_ptr<ElementBase>> l;
    };

    py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");

    py::class_<ElementA, std::shared_ptr<ElementA>>(m2, "ElementA", py::base<ElementBase>())
        .def(py::init<int>())
        .def("value", &ElementA::value);

    py::class_<ElementList, std::shared_ptr<ElementList>>(m2, "ElementList")
        .def(py::init<>())
        .def("add", &ElementList::add)
        .def("get", [](ElementList &el){
            py::list list;
            for (auto &e : el.l)
                list.append(py::cast(e));
            return list;
        });
104
105
106

    // (no id): should not be able to pass 'None' to a reference argument
    m2.def("print_element", [](ElementA &el) { std::cout << el.value() << std::endl; });
107
108
109
110

    // (no id): don't cast doubles to ints
    m2.def("expect_float", [](float f) { return f; });
    m2.def("expect_int", [](int i) { return i; });
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

    // (no id): don't invoke Python dispatch code when instantiating C++
    // classes that were not extended on the Python side
    struct A {
        virtual ~A() {}
        virtual void f() { std::cout << "A.f()" << std::endl; }
    };

    struct PyA : A {
        PyA() { std::cout << "PyA.PyA()" << std::endl; }

        void f() override {
            std::cout << "PyA.f()" << std::endl;
            PYBIND11_OVERLOAD(void, A, f);
        }
    };

    auto call_f = [](A *a) { a->f(); };

Wenzel Jakob's avatar
Wenzel Jakob committed
130
131
132
    pybind11::class_<A, std::unique_ptr<A>, PyA>(m2, "A")
        .def(py::init<>())
        .def("f", &A::f);
133

Wenzel Jakob's avatar
Wenzel Jakob committed
134
    m2.def("call_f", call_f);
135
136
137
138

    try {
        py::class_<Placeholder>(m2, "Placeholder");
        throw std::logic_error("Expected an exception!");
Dean Moldovan's avatar
Dean Moldovan committed
139
    } catch (std::runtime_error &) {
140
141
        /* All good */
    }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    // Issue #283: __str__ called on uninitialized instance when constructor arguments invalid
    class StrIssue {
    public:
        StrIssue(int i) : val{i} {}
        StrIssue() : StrIssue(-1) {}
        int value() const { return val; }
    private:
        int val;
    };
    py::class_<StrIssue> si(m2, "StrIssue");
    si  .def(py::init<int>())
        .def(py::init<>())
        .def("__str__", [](const StrIssue &si) {
                std::cout << "StrIssue.__str__ called" << std::endl;
                return "StrIssue[" + std::to_string(si.value()) + "]";
                })
        ;

161
162
163
164
165
166
167
168
169
170
171
172
    // Issue #328: first member in a class can't be used in operators
#define TRACKERS(CLASS) CLASS() { std::cout << #CLASS "@" << this << " constructor\n"; } \
                        ~CLASS() { std::cout << #CLASS "@" << this << " destructor\n"; }
    struct NestA { int value = 3; NestA& operator+=(int i) { value += i; return *this; } TRACKERS(NestA) };
    struct NestB { NestA a; int value = 4; NestB& operator-=(int i) { value -= i; return *this; } TRACKERS(NestB) };
    struct NestC { NestB b; int value = 5; NestC& operator*=(int i) { value *= i; return *this; } TRACKERS(NestC) };
    py::class_<NestA>(m2, "NestA").def(py::init<>()).def(py::self += int());
    py::class_<NestB>(m2, "NestB").def(py::init<>()).def(py::self -= int()).def_readwrite("a", &NestB::a);
    py::class_<NestC>(m2, "NestC").def(py::init<>()).def(py::self *= int()).def_readwrite("b", &NestC::b);
    m2.def("print_NestA", [](const NestA &a) { std::cout << a.value << std::endl; });
    m2.def("print_NestB", [](const NestB &b) { std::cout << b.value << std::endl; });
    m2.def("print_NestC", [](const NestC &c) { std::cout << c.value << std::endl; });
173
}