test_operator_overloading.cpp
Go to the documentation of this file.
1 /*
2  tests/test_operator_overloading.cpp -- operator overloading
3 
4  Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
5 
6  All rights reserved. Use of this source code is governed by a
7  BSD-style license that can be found in the LICENSE file.
8 */
9 
10 #include <pybind11/operators.h>
11 #include <pybind11/stl.h>
12 
13 #include "constructor_stats.h"
14 #include "pybind11_tests.h"
15 
16 #include <functional>
17 
18 class Vector2 {
19 public:
20  Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
21  Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
22  Vector2(Vector2 &&v) noexcept : x(v.x), y(v.y) {
23  print_move_created(this);
24  v.x = v.y = 0;
25  }
27  x = v.x;
28  y = v.y;
29  print_copy_assigned(this);
30  return *this;
31  }
32  Vector2 &operator=(Vector2 &&v) noexcept {
33  x = v.x;
34  y = v.y;
35  v.x = v.y = 0;
36  print_move_assigned(this);
37  return *this;
38  }
40 
41  std::string toString() const {
42  return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
43  }
44 
45  Vector2 operator-() const { return Vector2(-x, -y); }
46  Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
47  Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
48  Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
49  Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
50  Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
51  Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
52  Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
53  Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
55  x += v.x;
56  y += v.y;
57  return *this;
58  }
60  x -= v.x;
61  y -= v.y;
62  return *this;
63  }
64  Vector2 &operator*=(float v) {
65  x *= v;
66  y *= v;
67  return *this;
68  }
69  Vector2 &operator/=(float v) {
70  x /= v;
71  y /= v;
72  return *this;
73  }
75  x *= v.x;
76  y *= v.y;
77  return *this;
78  }
80  x /= v.x;
81  y /= v.y;
82  return *this;
83  }
84 
85  friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
86  friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
87  friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
88  friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
89 
90  bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; }
91  bool operator!=(const Vector2 &v) const { return x != v.x || y != v.y; }
92 
93 private:
94  float x, y;
95 };
96 
97 class C1 {};
98 class C2 {};
99 
100 int operator+(const C1 &, const C1 &) { return 11; }
101 int operator+(const C2 &, const C2 &) { return 22; }
102 int operator+(const C2 &, const C1 &) { return 21; }
103 int operator+(const C1 &, const C2 &) { return 12; }
104 
105 struct HashMe {
106  std::string member;
107 };
108 
109 bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs.member; }
110 
111 // Note: Specializing explicit within `namespace std { ... }` is done due to a
112 // bug in GCC<7. If you are supporting compilers later than this, consider
113 // specializing `using template<> struct std::hash<...>` in the global
114 // namespace instead, per this recommendation:
115 // https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
116 namespace std {
117 template <>
118 struct hash<Vector2> {
119  // Not a good hash function, but easy to test
120  size_t operator()(const Vector2 &) { return 4; }
121 };
122 
123 // HashMe has a hash function in C++ but no `__hash__` for Python.
124 template <>
125 struct hash<HashMe> {
126  std::size_t operator()(const HashMe &selector) const {
127  return std::hash<std::string>()(selector.member);
128  }
129 };
130 } // namespace std
131 
132 // Not a good abs function, but easy to test.
133 std::string abs(const Vector2 &) { return "abs(Vector2)"; }
134 
135 // MSVC & Intel warns about unknown pragmas, and warnings are errors.
136 #if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
137 # pragma GCC diagnostic push
138 // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
139 // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
140 // Here, we suppress the warning using `#pragma diagnostic`.
141 // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
142 // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
143 # if defined(__APPLE__) && defined(__clang__)
144 # if (__clang_major__ >= 10)
145 # pragma GCC diagnostic ignored "-Wself-assign-overloaded"
146 # endif
147 # elif defined(__clang__)
148 # if (__clang_major__ >= 7)
149 # pragma GCC diagnostic ignored "-Wself-assign-overloaded"
150 # endif
151 # endif
152 #endif
153 
154 TEST_SUBMODULE(operators, m) {
155 
156  // test_operator_overloading
157  py::class_<Vector2>(m, "Vector2")
158  .def(py::init<float, float>())
159  .def(py::self + py::self)
160  .def(py::self + float())
161  .def(py::self - py::self)
162  .def(py::self - float())
163  .def(py::self * float())
164  .def(py::self / float())
165  .def(py::self * py::self)
166  .def(py::self / py::self)
167  .def(py::self += py::self)
168  .def(py::self -= py::self)
169  .def(py::self *= float())
170  .def(py::self /= float())
171  .def(py::self *= py::self)
172  .def(py::self /= py::self)
173  .def(float() + py::self)
174  .def(float() - py::self)
175  .def(float() * py::self)
176  .def(float() / py::self)
177  .def(-py::self)
178  .def("__str__", &Vector2::toString)
179  .def("__repr__", &Vector2::toString)
180  .def(py::self == py::self)
181  .def(py::self != py::self)
182  .def(py::hash(py::self))
183  // N.B. See warning about usage of `py::detail::abs(py::self)` in
184  // `operators.h`.
185  .def("__abs__", [](const Vector2 &v) { return abs(v); });
186 
187  m.attr("Vector") = m.attr("Vector2");
188 
189  // test_operators_notimplemented
190  // #393: need to return NotSupported to ensure correct arithmetic operator behavior
191  py::class_<C1>(m, "C1").def(py::init<>()).def(py::self + py::self);
192 
193  py::class_<C2>(m, "C2")
194  .def(py::init<>())
195  .def(py::self + py::self)
196  .def("__add__", [](const C2 &c2, const C1 &c1) { return c2 + c1; })
197  .def("__radd__", [](const C2 &c2, const C1 &c1) { return c1 + c2; });
198 
199  // test_nested
200  // #328: first member in a class can't be used in operators
201  struct NestABase {
202  int value = -2;
203  };
204  py::class_<NestABase>(m, "NestABase")
205  .def(py::init<>())
206  .def_readwrite("value", &NestABase::value);
207 
208  struct NestA : NestABase {
209  int value = 3;
210  NestA &operator+=(int i) {
211  value += i;
212  return *this;
213  }
214  };
215  py::class_<NestA>(m, "NestA")
216  .def(py::init<>())
217  .def(py::self += int())
218  .def(
219  "as_base",
220  [](NestA &a) -> NestABase & { return (NestABase &) a; },
221  py::return_value_policy::reference_internal);
222  m.def("get_NestA", [](const NestA &a) { return a.value; });
223 
224  struct NestB {
225  NestA a;
226  int value = 4;
227  NestB &operator-=(int i) {
228  value -= i;
229  return *this;
230  }
231  };
232  py::class_<NestB>(m, "NestB")
233  .def(py::init<>())
234  .def(py::self -= int())
235  .def_readwrite("a", &NestB::a);
236  m.def("get_NestB", [](const NestB &b) { return b.value; });
237 
238  struct NestC {
239  NestB b;
240  int value = 5;
241  NestC &operator*=(int i) {
242  value *= i;
243  return *this;
244  }
245  };
246  py::class_<NestC>(m, "NestC")
247  .def(py::init<>())
248  .def(py::self *= int())
249  .def_readwrite("b", &NestC::b);
250  m.def("get_NestC", [](const NestC &c) { return c.value; });
251 
252  // test_overriding_eq_reset_hash
253  // #2191 Overriding __eq__ should set __hash__ to None
254  struct Comparable {
255  int value;
256  bool operator==(const Comparable &rhs) const { return value == rhs.value; }
257  };
258 
259  struct Hashable : Comparable {
260  explicit Hashable(int value) : Comparable{value} {};
261  size_t hash() const { return static_cast<size_t>(value); }
262  };
263 
264  struct Hashable2 : Hashable {
265  using Hashable::Hashable;
266  };
267 
268  py::class_<Comparable>(m, "Comparable").def(py::init<int>()).def(py::self == py::self);
269 
270  py::class_<Hashable>(m, "Hashable")
271  .def(py::init<int>())
272  .def(py::self == py::self)
273  .def("__hash__", &Hashable::hash);
274 
275  // define __hash__ before __eq__
276  py::class_<Hashable2>(m, "Hashable2")
277  .def("__hash__", &Hashable::hash)
278  .def(py::init<int>())
279  .def(py::self == py::self);
280 
281  // define __eq__ but not __hash__
282  py::class_<HashMe>(m, "HashMe").def(py::self == py::self);
283 
284  m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; });
285 }
286 #if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
287 # pragma GCC diagnostic pop
288 #endif
Matrix3f m
ssize_t hash(handle obj)
Definition: pytypes.h:792
bool operator!=(const Vector2 &v) const
Vector2 & operator/=(const Vector2 &v)
Vector2 operator+(float value) const
Scalar * b
Definition: benchVecAdd.cpp:17
Vector2 & operator*=(const Vector2 &v)
Vector2 operator-(const Vector2 &v) const
std::size_t operator()(const HashMe &selector) const
friend Vector2 operator-(float f, const Vector2 &v)
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
void print_destroyed(T *inst, Values &&...values)
static const self_t self
Definition: operators.h:72
Definition: BFloat16.h:88
void print_copy_assigned(T *inst, Values &&...values)
void print_copy_created(T *inst, Values &&...values)
Vector2(float x, float y)
Vector2 operator/(const Vector2 &v) const
Vector2 & operator+=(const Vector2 &v)
Vector2 operator-(float value) const
Vector2 operator+(const Vector2 &v) const
Vector2 operator/(float value) const
std::string toString() const
Vector2 operator*(float value) const
void print_move_assigned(T *inst, Values &&...values)
Vector2 & operator-=(const Vector2 &v)
Vector2(Vector2 &&v) noexcept
Vector2 & operator=(const Vector2 &v)
Vector2 & operator=(Vector2 &&v) noexcept
Array< int, Dynamic, 1 > v
TEST_SUBMODULE(operators, m)
Vector2 & operator/=(float v)
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
std::string abs(const Vector2 &)
friend Vector2 operator/(float f, const Vector2 &v)
friend Vector2 operator+(float f, const Vector2 &v)
friend Vector2 operator*(float f, const Vector2 &v)
Vector2 operator*(const Vector2 &v) const
size_t operator()(const Vector2 &)
void print_created(T *inst, Values &&...values)
Vector2 & operator*=(float v)
Vector2(const Vector2 &v)
bool operator==(const Vector2 &v) const
void print_move_created(T *inst, Values &&...values)
Vector2 operator-() const


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:37:46