Fix def_property and related functions

Making `cppfunction` explicit broke `def_property` and friends.
The added tests would not compile without an implicit `cppfunction`.
This commit is contained in:
Dean Moldovan 2016-10-21 18:51:14 +02:00
parent 77898af0f8
commit 5b7e190fa2
3 changed files with 69 additions and 4 deletions

View File

@ -44,12 +44,12 @@ public:
/// Construct a cpp_function from a vanilla function pointer /// Construct a cpp_function from a vanilla function pointer
template <typename Return, typename... Args, typename... Extra> template <typename Return, typename... Args, typename... Extra>
explicit cpp_function(Return (*f)(Args...), const Extra&... extra) { cpp_function(Return (*f)(Args...), const Extra&... extra) {
initialize(f, f, extra...); initialize(f, f, extra...);
} }
/// Construct a cpp_function from a lambda function (possibly with internal state) /// Construct a cpp_function from a lambda function (possibly with internal state)
template <typename Func, typename... Extra> explicit cpp_function(Func &&f, const Extra&... extra) { template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) {
initialize(std::forward<Func>(f), initialize(std::forward<Func>(f),
(typename detail::remove_class<decltype( (typename detail::remove_class<decltype(
&std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...); &std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...);
@ -57,14 +57,14 @@ public:
/// Construct a cpp_function from a class method (non-const) /// Construct a cpp_function from a class method (non-const)
template <typename Return, typename Class, typename... Arg, typename... Extra> template <typename Return, typename Class, typename... Arg, typename... Extra>
explicit cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) { cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) {
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); }, initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
(Return (*) (Class *, Arg...)) nullptr, extra...); (Return (*) (Class *, Arg...)) nullptr, extra...);
} }
/// Construct a cpp_function from a class method (const) /// Construct a cpp_function from a class method (const)
template <typename Return, typename Class, typename... Arg, typename... Extra> template <typename Return, typename Class, typename... Arg, typename... Extra>
explicit cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) { cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); }, initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
(Return (*)(const Class *, Arg ...)) nullptr, extra...); (Return (*)(const Class *, Arg ...)) nullptr, extra...);
} }

View File

@ -53,6 +53,19 @@ public:
int value = 0; int value = 0;
}; };
struct TestProperties {
int value = 1;
static int static_value;
int get() const { return value; }
void set(int v) { value = v; }
static int static_get() { return static_value; }
static void static_set(int v) { static_value = v; }
};
int TestProperties::static_value = 1;
class DynamicClass { class DynamicClass {
public: public:
DynamicClass() { print_default_created(this); } DynamicClass() { print_default_created(this); }
@ -90,6 +103,20 @@ test_initializer methods_and_attributes([](py::module &m) {
.def_readwrite("value", &ExampleMandA::value) .def_readwrite("value", &ExampleMandA::value)
; ;
py::class_<TestProperties>(m, "TestProperties")
.def(py::init<>())
.def_readonly("def_readonly", &TestProperties::value)
.def_readwrite("def_readwrite", &TestProperties::value)
.def_property_readonly("def_property_readonly", &TestProperties::get)
.def_property("def_property", &TestProperties::get, &TestProperties::set)
.def_readonly_static("def_readonly_static", &TestProperties::static_value)
.def_readwrite_static("def_readwrite_static", &TestProperties::static_value)
.def_property_readonly_static("def_property_readonly_static",
[](py::object) { return TestProperties::static_get(); })
.def_property_static("def_property_static",
[](py::object) { return TestProperties::static_get(); },
[](py::object, int v) { return TestProperties::static_set(v); });
py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr()) py::class_<DynamicClass>(m, "DynamicClass", py::dynamic_attr())
.def(py::init()); .def(py::init());

View File

@ -47,6 +47,44 @@ def test_methods_and_attributes():
assert cstats.move_assignments == 0 assert cstats.move_assignments == 0
def test_properties():
from pybind11_tests import TestProperties
instance = TestProperties()
assert instance.def_readonly == 1
with pytest.raises(AttributeError):
instance.def_readonly = 2
instance.def_readwrite = 2
assert instance.def_readwrite == 2
assert instance.def_property_readonly == 2
with pytest.raises(AttributeError):
instance.def_property_readonly = 3
instance.def_property = 3
assert instance.def_property == 3
def test_static_properties():
from pybind11_tests import TestProperties as Type
assert Type.def_readonly_static == 1
with pytest.raises(AttributeError):
Type.def_readonly_static = 2
Type.def_readwrite_static = 2
assert Type.def_readwrite_static == 2
assert Type.def_property_readonly_static == 2
with pytest.raises(AttributeError):
Type.def_property_readonly_static = 3
Type.def_property_static = 3
assert Type.def_property_static == 3
def test_dynamic_attributes(): def test_dynamic_attributes():
from pybind11_tests import DynamicClass, CppDerivedDynamicClass from pybind11_tests import DynamicClass, CppDerivedDynamicClass