From d41a273031770112fdec6fb03e8259c4b103e23a Mon Sep 17 00:00:00 2001 From: Jason Rhinelander Date: Thu, 4 Aug 2016 00:21:37 -0400 Subject: [PATCH] Only support ==/!= int on unscoped enums This makes the Python interface mirror the C++ interface: pybind11-exported scoped enums aren't directly comparable to the underlying integer values. --- example/example-constants-and-functions.py | 21 ++++++++++++++++++++- example/example-constants-and-functions.ref | 2 ++ include/pybind11/pybind11.h | 9 +++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/example/example-constants-and-functions.py b/example/example-constants-and-functions.py index 0a5224a02..852902f07 100755 --- a/example/example-constants-and-functions.py +++ b/example/example-constants-and-functions.py @@ -22,7 +22,26 @@ print(test_function(7)) print(test_function(EMyEnumeration.EFirstEntry)) print(test_function(EMyEnumeration.ESecondEntry)) test_ecenum(ECMyEnum.Three) -test_ecenum(ECMyEnum.Two) +z = ECMyEnum.Two +test_ecenum(z) +try: + z == 2 + print("Bad: expected a TypeError exception") +except TypeError: + try: + z != 3 + print("Bad: expected a TypeError exception") + except TypeError: + print("Good: caught expected TypeError exceptions for scoped enum ==/!= int comparisons") + +y = EMyEnumeration.ESecondEntry +try: + y == 2 + y != 2 + print("Good: no TypeError exception for unscoped enum ==/!= int comparisions") +except TypeError: + print("Bad: caught TypeError exception for unscoped enum ==/!= int comparisons") + print("enum->integer = %i" % int(EMyEnumeration.ESecondEntry)) print("integer->enum = %s" % str(EMyEnumeration(2))) diff --git a/example/example-constants-and-functions.ref b/example/example-constants-and-functions.ref index f82480694..480563114 100644 --- a/example/example-constants-and-functions.ref +++ b/example/example-constants-and-functions.ref @@ -12,6 +12,8 @@ test_function(enum=2) None test_ecenum(ECMyEnum::Three) test_ecenum(ECMyEnum::Two) +Good: caught expected TypeError exceptions for scoped enum ==/!= int comparisons +Good: no TypeError exception for unscoped enum ==/!= int comparisions enum->integer = 2 integer->enum = EMyEnumeration.ESecondEntry A constant = 14 diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 6bab4a95e..bfb0f07ad 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1019,9 +1019,14 @@ public: this->def("__init__", [](Type& value, UnderlyingType i) { new (&value) Type((Type) i); }); this->def("__int__", [](Type value) { return (UnderlyingType) value; }); this->def("__eq__", [](const Type &value, Type *value2) { return value2 && value == *value2; }); - this->def("__eq__", [](const Type &value, UnderlyingType value2) { return (UnderlyingType) value == value2; }); this->def("__ne__", [](const Type &value, Type *value2) { return !value2 || value != *value2; }); - this->def("__ne__", [](const Type &value, UnderlyingType value2) { return (UnderlyingType) value != value2; }); + if (std::is_convertible::value) { + // Don't provide comparison with the underlying type if the enum isn't convertible, + // i.e. if Type is a scoped enum, mirroring the C++ behaviour. (NB: we explicitly + // convert Type to UnderlyingType below anyway because this needs to compile). + this->def("__eq__", [](const Type &value, UnderlyingType value2) { return (UnderlyingType) value == value2; }); + this->def("__ne__", [](const Type &value, UnderlyingType value2) { return (UnderlyingType) value != value2; }); + } this->def("__hash__", [](const Type &value) { return (UnderlyingType) value; }); m_entries = entries; }