Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
7b067cc3
Unverified
Commit
7b067cc3
authored
Jul 27, 2020
by
Sergei Izmailov
Committed by
GitHub
Jul 27, 2020
Browse files
Set __hash__ to None for types that defines __eq__, but not __hash__ (#2291)
fixes #2191
parent
aab70139
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
56 additions
and
1 deletion
+56
-1
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+8
-1
tests/test_operator_overloading.cpp
tests/test_operator_overloading.cpp
+32
-0
tests/test_operator_overloading.py
tests/test_operator_overloading.py
+16
-0
No files found.
include/pybind11/pybind11.h
View file @
7b067cc3
...
@@ -1047,6 +1047,13 @@ inline void call_operator_delete(void *p, size_t s, size_t a) {
...
@@ -1047,6 +1047,13 @@ inline void call_operator_delete(void *p, size_t s, size_t a) {
#endif
#endif
}
}
inline
void
add_class_method
(
object
&
cls
,
const
char
*
name_
,
const
cpp_function
&
cf
)
{
cls
.
attr
(
cf
.
name
())
=
cf
;
if
(
strcmp
(
name_
,
"__eq__"
)
==
0
&&
!
cls
.
attr
(
"__dict__"
).
contains
(
"__hash__"
))
{
cls
.
attr
(
"__hash__"
)
=
none
();
}
}
PYBIND11_NAMESPACE_END
(
detail
)
PYBIND11_NAMESPACE_END
(
detail
)
/// Given a pointer to a member function, cast it to its `Derived` version.
/// Given a pointer to a member function, cast it to its `Derived` version.
...
@@ -1144,7 +1151,7 @@ public:
...
@@ -1144,7 +1151,7 @@ public:
class_
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
class_
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
cpp_function
cf
(
method_adaptor
<
type
>
(
std
::
forward
<
Func
>
(
f
)),
name
(
name_
),
is_method
(
*
this
),
cpp_function
cf
(
method_adaptor
<
type
>
(
std
::
forward
<
Func
>
(
f
)),
name
(
name_
),
is_method
(
*
this
),
sibling
(
getattr
(
*
this
,
name_
,
none
())),
extra
...);
sibling
(
getattr
(
*
this
,
name_
,
none
())),
extra
...);
a
ttr
(
cf
.
name
())
=
cf
;
a
dd_class_method
(
*
this
,
name_
,
cf
)
;
return
*
this
;
return
*
this
;
}
}
...
...
tests/test_operator_overloading.cpp
View file @
7b067cc3
...
@@ -187,6 +187,38 @@ TEST_SUBMODULE(operators, m) {
...
@@ -187,6 +187,38 @@ TEST_SUBMODULE(operators, m) {
.
def
(
py
::
self
*=
int
())
.
def
(
py
::
self
*=
int
())
.
def_readwrite
(
"b"
,
&
NestC
::
b
);
.
def_readwrite
(
"b"
,
&
NestC
::
b
);
m
.
def
(
"get_NestC"
,
[](
const
NestC
&
c
)
{
return
c
.
value
;
});
m
.
def
(
"get_NestC"
,
[](
const
NestC
&
c
)
{
return
c
.
value
;
});
// test_overriding_eq_reset_hash
// #2191 Overriding __eq__ should set __hash__ to None
struct
Comparable
{
int
value
;
bool
operator
==
(
const
Comparable
&
rhs
)
const
{
return
value
==
rhs
.
value
;}
};
struct
Hashable
:
Comparable
{
explicit
Hashable
(
int
value
)
:
Comparable
{
value
}{};
size_t
hash
()
const
{
return
static_cast
<
size_t
>
(
value
);
}
};
struct
Hashable2
:
Hashable
{
using
Hashable
::
Hashable
;
};
py
::
class_
<
Comparable
>
(
m
,
"Comparable"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
py
::
self
==
py
::
self
);
py
::
class_
<
Hashable
>
(
m
,
"Hashable"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
py
::
self
==
py
::
self
)
.
def
(
"__hash__"
,
&
Hashable
::
hash
);
// define __hash__ before __eq__
py
::
class_
<
Hashable2
>
(
m
,
"Hashable2"
)
.
def
(
"__hash__"
,
&
Hashable
::
hash
)
.
def
(
py
::
init
<
int
>
())
.
def
(
py
::
self
==
py
::
self
);
}
}
#ifndef _MSC_VER
#ifndef _MSC_VER
...
...
tests/test_operator_overloading.py
View file @
7b067cc3
...
@@ -127,3 +127,19 @@ def test_nested():
...
@@ -127,3 +127,19 @@ def test_nested():
assert
abase
.
value
==
42
assert
abase
.
value
==
42
del
abase
,
b
del
abase
,
b
pytest
.
gc_collect
()
pytest
.
gc_collect
()
def
test_overriding_eq_reset_hash
():
assert
m
.
Comparable
(
15
)
is
not
m
.
Comparable
(
15
)
assert
m
.
Comparable
(
15
)
==
m
.
Comparable
(
15
)
with
pytest
.
raises
(
TypeError
):
hash
(
m
.
Comparable
(
15
))
# TypeError: unhashable type: 'm.Comparable'
for
hashable
in
(
m
.
Hashable
,
m
.
Hashable2
):
assert
hashable
(
15
)
is
not
hashable
(
15
)
assert
hashable
(
15
)
==
hashable
(
15
)
assert
hash
(
hashable
(
15
))
==
15
assert
hash
(
hashable
(
15
))
==
hash
(
hashable
(
15
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment