test_operator_overloading.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. tests/test_operator_overloading.cpp -- operator overloading
  3. Copyright (c) 2016 Wenzel Jakob <[email protected]>
  4. All rights reserved. Use of this source code is governed by a
  5. BSD-style license that can be found in the LICENSE file.
  6. */
  7. #include "pybind11_tests.h"
  8. #include "constructor_stats.h"
  9. #include <pybind11/operators.h>
  10. #include <functional>
  11. class Vector2 {
  12. public:
  13. Vector2(float x, float y) : x(x), y(y) { print_created(this, toString()); }
  14. Vector2(const Vector2 &v) : x(v.x), y(v.y) { print_copy_created(this); }
  15. Vector2(Vector2 &&v) : x(v.x), y(v.y) { print_move_created(this); v.x = v.y = 0; }
  16. Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; }
  17. Vector2 &operator=(Vector2 &&v) { x = v.x; y = v.y; v.x = v.y = 0; print_move_assigned(this); return *this; }
  18. ~Vector2() { print_destroyed(this); }
  19. std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; }
  20. Vector2 operator-() const { return Vector2(-x, -y); }
  21. Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
  22. Vector2 operator-(const Vector2 &v) const { return Vector2(x - v.x, y - v.y); }
  23. Vector2 operator-(float value) const { return Vector2(x - value, y - value); }
  24. Vector2 operator+(float value) const { return Vector2(x + value, y + value); }
  25. Vector2 operator*(float value) const { return Vector2(x * value, y * value); }
  26. Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
  27. Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
  28. Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
  29. Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
  30. Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; }
  31. Vector2& operator*=(float v) { x *= v; y *= v; return *this; }
  32. Vector2& operator/=(float v) { x /= v; y /= v; return *this; }
  33. Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; }
  34. Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; }
  35. friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
  36. friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
  37. friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
  38. friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
  39. bool operator==(const Vector2 &v) const {
  40. return x == v.x && y == v.y;
  41. }
  42. bool operator!=(const Vector2 &v) const {
  43. return x != v.x || y != v.y;
  44. }
  45. private:
  46. float x, y;
  47. };
  48. class C1 { };
  49. class C2 { };
  50. int operator+(const C1 &, const C1 &) { return 11; }
  51. int operator+(const C2 &, const C2 &) { return 22; }
  52. int operator+(const C2 &, const C1 &) { return 21; }
  53. int operator+(const C1 &, const C2 &) { return 12; }
  54. // Note: Specializing explicit within `namespace std { ... }` is done due to a
  55. // bug in GCC<7. If you are supporting compilers later than this, consider
  56. // specializing `using template<> struct std::hash<...>` in the global
  57. // namespace instead, per this recommendation:
  58. // https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
  59. namespace std {
  60. template<>
  61. struct hash<Vector2> {
  62. // Not a good hash function, but easy to test
  63. size_t operator()(const Vector2 &) { return 4; }
  64. };
  65. } // namespace std
  66. // Not a good abs function, but easy to test.
  67. std::string abs(const Vector2&) {
  68. return "abs(Vector2)";
  69. }
  70. // MSVC warns about unknown pragmas, and warnings are errors.
  71. #ifndef _MSC_VER
  72. #pragma GCC diagnostic push
  73. // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
  74. // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
  75. // Here, we suppress the warning using `#pragma diagnostic`.
  76. // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
  77. // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
  78. #if defined(__APPLE__) && defined(__clang__)
  79. #if (__clang_major__ >= 10)
  80. #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
  81. #endif
  82. #elif defined(__clang__)
  83. #if (__clang_major__ >= 7)
  84. #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
  85. #endif
  86. #endif
  87. #endif
  88. TEST_SUBMODULE(operators, m) {
  89. // test_operator_overloading
  90. py::class_<Vector2>(m, "Vector2")
  91. .def(py::init<float, float>())
  92. .def(py::self + py::self)
  93. .def(py::self + float())
  94. .def(py::self - py::self)
  95. .def(py::self - float())
  96. .def(py::self * float())
  97. .def(py::self / float())
  98. .def(py::self * py::self)
  99. .def(py::self / py::self)
  100. .def(py::self += py::self)
  101. .def(py::self -= py::self)
  102. .def(py::self *= float())
  103. .def(py::self /= float())
  104. .def(py::self *= py::self)
  105. .def(py::self /= py::self)
  106. .def(float() + py::self)
  107. .def(float() - py::self)
  108. .def(float() * py::self)
  109. .def(float() / py::self)
  110. .def(-py::self)
  111. .def("__str__", &Vector2::toString)
  112. .def("__repr__", &Vector2::toString)
  113. .def(py::self == py::self)
  114. .def(py::self != py::self)
  115. .def(py::hash(py::self))
  116. // N.B. See warning about usage of `py::detail::abs(py::self)` in
  117. // `operators.h`.
  118. .def("__abs__", [](const Vector2& v) { return abs(v); })
  119. ;
  120. m.attr("Vector") = m.attr("Vector2");
  121. // test_operators_notimplemented
  122. // #393: need to return NotSupported to ensure correct arithmetic operator behavior
  123. py::class_<C1>(m, "C1")
  124. .def(py::init<>())
  125. .def(py::self + py::self);
  126. py::class_<C2>(m, "C2")
  127. .def(py::init<>())
  128. .def(py::self + py::self)
  129. .def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; })
  130. .def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; });
  131. // test_nested
  132. // #328: first member in a class can't be used in operators
  133. struct NestABase { int value = -2; };
  134. py::class_<NestABase>(m, "NestABase")
  135. .def(py::init<>())
  136. .def_readwrite("value", &NestABase::value);
  137. struct NestA : NestABase {
  138. int value = 3;
  139. NestA& operator+=(int i) { value += i; return *this; }
  140. };
  141. py::class_<NestA>(m, "NestA")
  142. .def(py::init<>())
  143. .def(py::self += int())
  144. .def("as_base", [](NestA &a) -> NestABase& {
  145. return (NestABase&) a;
  146. }, py::return_value_policy::reference_internal);
  147. m.def("get_NestA", [](const NestA &a) { return a.value; });
  148. struct NestB {
  149. NestA a;
  150. int value = 4;
  151. NestB& operator-=(int i) { value -= i; return *this; }
  152. };
  153. py::class_<NestB>(m, "NestB")
  154. .def(py::init<>())
  155. .def(py::self -= int())
  156. .def_readwrite("a", &NestB::a);
  157. m.def("get_NestB", [](const NestB &b) { return b.value; });
  158. struct NestC {
  159. NestB b;
  160. int value = 5;
  161. NestC& operator*=(int i) { value *= i; return *this; }
  162. };
  163. py::class_<NestC>(m, "NestC")
  164. .def(py::init<>())
  165. .def(py::self *= int())
  166. .def_readwrite("b", &NestC::b);
  167. m.def("get_NestC", [](const NestC &c) { return c.value; });
  168. // test_overriding_eq_reset_hash
  169. // #2191 Overriding __eq__ should set __hash__ to None
  170. struct Comparable {
  171. int value;
  172. bool operator==(const Comparable& rhs) const {return value == rhs.value;}
  173. };
  174. struct Hashable : Comparable {
  175. explicit Hashable(int value): Comparable{value}{};
  176. size_t hash() const { return static_cast<size_t>(value); }
  177. };
  178. struct Hashable2 : Hashable {
  179. using Hashable::Hashable;
  180. };
  181. py::class_<Comparable>(m, "Comparable")
  182. .def(py::init<int>())
  183. .def(py::self == py::self);
  184. py::class_<Hashable>(m, "Hashable")
  185. .def(py::init<int>())
  186. .def(py::self == py::self)
  187. .def("__hash__", &Hashable::hash);
  188. // define __hash__ before __eq__
  189. py::class_<Hashable2>(m, "Hashable2")
  190. .def("__hash__", &Hashable::hash)
  191. .def(py::init<int>())
  192. .def(py::self == py::self);
  193. }
  194. #ifndef _MSC_VER
  195. #pragma GCC diagnostic pop
  196. #endif