From c530ea4952743a2983d3d83ffe087715b1a90fa5 Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Sat, 19 Sep 2020 15:44:02 -0400 Subject: [PATCH] WIP Show edge case with operator overloading, reversal, and mixing --- docs/advanced/classes.rst | 2 +- tests/test_operator_overloading.cpp | 21 +++++++++++++++++++++ tests/test_operator_overloading.py | 6 ++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/advanced/classes.rst b/docs/advanced/classes.rst index 4927902069..070a0121d7 100644 --- a/docs/advanced/classes.rst +++ b/docs/advanced/classes.rst @@ -748,7 +748,7 @@ throwing a type error. The file :file:`tests/test_operator_overloading.cpp` contains a complete example that demonstrates how to work with overloaded operators in - more detail. + more detail, as well of some of the nuances you may encounter. .. _pickling: diff --git a/tests/test_operator_overloading.cpp b/tests/test_operator_overloading.cpp index 0a27bfd57b..91ba39c6dd 100644 --- a/tests/test_operator_overloading.cpp +++ b/tests/test_operator_overloading.cpp @@ -62,6 +62,8 @@ int operator+(const C2 &, const C2 &) { return 22; } int operator+(const C2 &, const C1 &) { return 21; } int operator+(const C1 &, const C2 &) { return 12; } + + // Note: Specializing explicit within `namespace std { ... }` is done due to a // bug in GCC<7. If you are supporting compilers later than this, consider // specializing `using template<> struct std::hash<...>` in the global @@ -80,6 +82,17 @@ std::string abs(const Vector2&) { return "abs(Vector2)"; } +// ReverseA and ReverseB simulate two classes defined in separate files, both +// with oeprator overloads on +, and ReverseB wishes to overload __radd__ with +// ReversedA. This won't work, as will be shown in the Python test. +struct ReverseA { + friend int operator+(int, ReverseA) { return 1; }; +}; +struct ReverseB { + friend int operator+(ReverseB, ReverseA) { return 2; }; + friend int operator+(ReverseA, ReverseB) { return 3; }; +}; + // MSVC warns about unknown pragmas, and warnings are errors. #ifndef _MSC_VER #pragma GCC diagnostic push @@ -219,6 +232,14 @@ TEST_SUBMODULE(operators, m) { .def("__hash__", &Hashable::hash) .def(py::init()) .def(py::self == py::self); + + py::class_(m, "ReverseA") + .def(py::init()) + .def(int{} + py::self); + py::class_(m, "ReverseB") + .def(py::init()) + .def(py::self + ReverseA{}) + .def(ReverseA{} + py::self); } #ifndef _MSC_VER diff --git a/tests/test_operator_overloading.py b/tests/test_operator_overloading.py index 39e3aee271..eb2488abb0 100644 --- a/tests/test_operator_overloading.py +++ b/tests/test_operator_overloading.py @@ -143,3 +143,9 @@ def test_overriding_eq_reset_hash(): assert hash(hashable(15)) == 15 assert hash(hashable(15)) == hash(hashable(15)) + + +def test_reverse_operator_ambiguity(): + assert int() + m.ReverseA() == 1 + assert m.ReverseB() + m.ReverseA() == 2 + assert m.ReverseA() + m.ReverseB() == 3