test_operator_overloading.cpp 5.22 KB
Newer Older
Wenzel Jakob's avatar
Wenzel Jakob committed
1
/*
Dean Moldovan's avatar
Dean Moldovan committed
2
    tests/test_operator_overloading.cpp -- operator overloading
Wenzel Jakob's avatar
Wenzel Jakob committed
3

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

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

Dean Moldovan's avatar
Dean Moldovan committed
10
11
#include "pybind11_tests.h"
#include "constructor_stats.h"
12
#include <pybind11/operators.h>
Wenzel Jakob's avatar
Wenzel Jakob committed
13
14
15

class Vector2 {
public:
16
17
18
19
    Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
    Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
    Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
    ~Vector2() { print_destroyed(this); }
Wenzel Jakob's avatar
Wenzel Jakob committed
20
21
22
23
24
25

    std::string toString() const {
        return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
    }

    void operator=(const Vector2 &v) {
26
        print_copy_assigned(this);
Wenzel Jakob's avatar
Wenzel Jakob committed
27
28
29
30
31
        x = v.x;
        y = v.y;
    }

    void operator=(Vector2 &&v) {
32
        print_move_assigned(this);
Wenzel Jakob's avatar
Wenzel Jakob committed
33
34
35
36
37
38
39
40
41
        x = v.x; y = v.y; v.x = v.y = 0;
    }

    Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
    Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
    Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
    Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
    Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
    Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
42
43
    Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
    Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
Wenzel Jakob's avatar
Wenzel Jakob committed
44
45
46
47
    Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
    Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
    Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
    Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
48
49
    Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; }
    Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; }
50
51
52
53
54

    friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
    friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
    friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
    friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
Wenzel Jakob's avatar
Wenzel Jakob committed
55
56
57
58
private:
    float x, y;
};

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class C1 { };
class C2 { };

int operator+(const C1 &, const C1 &) { return 11; }
int operator+(const C2 &, const C2 &) { return 22; }
int operator+(const C2 &, const C1 &) { return 21; }
int operator+(const C1 &, const C2 &) { return 12; }

struct NestABase {
    int value = -2;
};

struct NestA : NestABase {
    int value = 3;
    NestA& operator+=(int i) { value += i; return *this; }
};

struct NestB {
    NestA a;
    int value = 4;
    NestB& operator-=(int i) { value -= i; return *this; }
};

struct NestC {
    NestB b;
    int value = 5;
    NestC& operator*=(int i) { value *= i; return *this; }
};

test_initializer operator_overloading([](py::module &pm) {
    auto m = pm.def_submodule("operators");

Wenzel Jakob's avatar
Wenzel Jakob committed
91
92
93
94
95
96
97
98
    py::class_<Vector2>(m, "Vector2")
        .def(py::init<float, float>())
        .def(py::self + py::self)
        .def(py::self + float())
        .def(py::self - py::self)
        .def(py::self - float())
        .def(py::self * float())
        .def(py::self / float())
99
100
        .def(py::self * py::self)
        .def(py::self / py::self)
Wenzel Jakob's avatar
Wenzel Jakob committed
101
102
103
104
        .def(py::self += py::self)
        .def(py::self -= py::self)
        .def(py::self *= float())
        .def(py::self /= float())
105
106
        .def(py::self *= py::self)
        .def(py::self /= py::self)
107
108
109
110
        .def(float() + py::self)
        .def(float() - py::self)
        .def(float() * py::self)
        .def(float() / py::self)
111
112
        .def("__str__", &Vector2::toString)
        ;
Wenzel Jakob's avatar
Wenzel Jakob committed
113
114

    m.attr("Vector") = m.attr("Vector2");
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

    // #393: need to return NotSupported to ensure correct arithmetic operator behavior
    py::class_<C1>(m, "C1")
        .def(py::init<>())
        .def(py::self + py::self);

    py::class_<C2>(m, "C2")
        .def(py::init<>())
        .def(py::self + py::self)
        .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
        .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });

    // #328: first member in a class can't be used in operators
    py::class_<NestABase>(m, "NestABase")
        .def(py::init<>())
        .def_readwrite("value", &NestABase::value);

    py::class_<NestA>(m, "NestA")
        .def(py::init<>())
        .def(py::self += int())
        .def("as_base", [](NestA &a) -> NestABase& {
            return (NestABase&) a;
        }, py::return_value_policy::reference_internal);

    py::class_<NestB>(m, "NestB")
        .def(py::init<>())
        .def(py::self -= int())
        .def_readwrite("a", &NestB::a);

    py::class_<NestC>(m, "NestC")
        .def(py::init<>())
        .def(py::self *= int())
        .def_readwrite("b", &NestC::b);

    m.def("get_NestA", [](const NestA &a) { return a.value; });
    m.def("get_NestB", [](const NestB &b) { return b.value; });
    m.def("get_NestC", [](const NestC &c) { return c.value; });
152
});