diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index a1fcf4fd..999632bf 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -127,7 +127,6 @@ namespace detail register_wrapper_class_impl((Held*)0, (T*)0, 0); } -# ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING template struct is_data_member_pointer : mpl::and_< @@ -135,15 +134,17 @@ namespace detail , mpl::not_ > > {}; -# define BOOST_PYTHON_DATA_MEMBER_HELPER , detail::is_data_member_pointer() + +# ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING +# define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , detail::is_data_member_pointer() # define BOOST_PYTHON_YES_DATA_MEMBER , mpl::true_ # define BOOST_PYTHON_NO_DATA_MEMBER , mpl::false_ # elif defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -# define BOOST_PYTHON_DATA_MEMBER_HELPER , 0 +# define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , 0 # define BOOST_PYTHON_YES_DATA_MEMBER , int # define BOOST_PYTHON_NO_DATA_MEMBER , ... # else -# define BOOST_PYTHON_DATA_MEMBER_HELPER +# define BOOST_PYTHON_DATA_MEMBER_HELPER(D) # define BOOST_PYTHON_YES_DATA_MEMBER # define BOOST_PYTHON_NO_DATA_MEMBER # endif @@ -337,39 +338,39 @@ class class_ : public objects::class_base template self& def_readonly(char const* name, D const& d) { - return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER); + return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D)); } template self& def_readwrite(char const* name, D const& d) { - return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER); + return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D)); } template self& def_readonly(char const* name, D& d) { - return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER); + return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D)); } template self& def_readwrite(char const* name, D& d) { - return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER); + return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D)); } // Property creation template self& add_property(char const* name, Get fget) { - base::add_property(name, make_fn(fget)); + base::add_property(name, this->make_getter(fget)); return *this; } template self& add_property(char const* name, Get fget, Set fset) { - base::add_property(name, make_fn(fget), make_fn(fset)); + base::add_property(name, this->make_getter(fget), this->make_setter(fset)); return *this; } @@ -415,25 +416,55 @@ class class_ : public objects::class_base } private: // helper functions - // Builds a method for this class around the given [member] // function pointer or object, appropriately adjusting the type of // the first signature argument so that if f is a member of a // (possibly not wrapped) base class of T, an lvalue argument of // type T will be required. // - // @group make_fn { + // @group PropertyHelpers { template - object make_fn(F const& f) + object make_getter(F f) { - return make_function(f, default_call_policies(), detail::get_signature(f, (T*)0)); + typedef typename api::is_object_operators::type is_obj_or_proxy; + + return this->make_fn_impl( + f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer() + ); + } + + template + object make_setter(F f) + { + typedef typename api::is_object_operators::type is_obj_or_proxy; + + return this->make_fn_impl( + f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer() + ); + } + + template + object make_fn_impl(F const& f, mpl::false_, void*, mpl::false_) + { + return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0)); } - object -# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) - const& -# endif - make_fn(object const& x) + template + object make_fn_impl(D B::*pm_, mpl::false_, char*, mpl::true_) + { + D T::*pm = pm_; + return python::make_getter(pm); + } + + template + object make_fn_impl(D B::*pm_, mpl::false_, int*, mpl::true_) + { + D T::*pm = pm_; + return python::make_setter(pm); + } + + template + object make_fn_impl(F const& x, mpl::true_, void*, mpl::false_) { return x; } @@ -443,30 +474,28 @@ class class_ : public objects::class_base self& def_readonly_impl( char const* name, D B::*pm_ BOOST_PYTHON_YES_DATA_MEMBER) { - D T::*pm = pm_; - return this->add_property(name, make_getter(pm)); + return this->add_property(name, pm_); } template self& def_readwrite_impl( char const* name, D B::*pm_ BOOST_PYTHON_YES_DATA_MEMBER) { - D T::*pm = pm_; - return this->add_property(name, make_getter(pm), make_setter(pm)); + return this->add_property(name, pm_, pm_); } template self& def_readonly_impl( char const* name, D& d BOOST_PYTHON_NO_DATA_MEMBER) { - return this->add_static_property(name, make_getter(d)); + return this->add_static_property(name, python::make_getter(d)); } template self& def_readwrite_impl( char const* name, D& d BOOST_PYTHON_NO_DATA_MEMBER) { - return this->add_static_property(name, make_getter(d), make_setter(d)); + return this->add_static_property(name, python::make_getter(d), python::make_setter(d)); } inline void register_() const; diff --git a/include/boost/python/object_operators.hpp b/include/boost/python/object_operators.hpp index 358b0b76..9bf6a6a8 100644 --- a/include/boost/python/object_operators.hpp +++ b/include/boost/python/object_operators.hpp @@ -17,8 +17,6 @@ namespace boost { namespace python { namespace api { -# if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) - template char is_object_operators_helper(object_operators const*); @@ -27,7 +25,7 @@ no_type is_object_operators_helper(...); template X* make_ptr(); -template +template struct is_object_operators { enum { @@ -40,6 +38,7 @@ struct is_object_operators typedef mpl::bool_ type; }; +# if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) template struct enable_binary : boost::iterators::enable_if, T> diff --git a/test/properties.cpp b/test/properties.cpp index fdfa43a5..234601ad 100755 --- a/test/properties.cpp +++ b/test/properties.cpp @@ -2,6 +2,26 @@ using namespace boost::python; +namespace test { + +// Hmm. return_internal_reference<>() wants to wrap a real class. +class ret_type +{ + public: + ret_type() : i(42.5) {} + double i; +}; + +class crash_me +{ + private: + ret_type i; + public: + ret_type& get_i() { return i; } +}; + +} + struct X { X( int value ) : m_value( value ) @@ -55,6 +75,20 @@ BOOST_PYTHON_MODULE(properties_ext) make_setter( &X::s_count, return_by_internal_reference_t() ) ) //defining class property using a global function .add_static_property( "instance_count_injected", &get_X_instance_count ); + + + class_< test::ret_type>( "ret_type") + .add_property( "i", &test::ret_type::i, &test::ret_type::i) + ; + + class_< test::crash_me> crash_me_wrapper( "crash_me"); + + crash_me_wrapper + .def( "get_i", &test::crash_me::get_i , return_internal_reference<>()) + ; + + crash_me_wrapper.add_property( "i", crash_me_wrapper.attr("get_i")); + } #include "module_tail.cpp" diff --git a/test/properties.py b/test/properties.py index ffceb4d6..527475d5 100644 --- a/test/properties.py +++ b/test/properties.py @@ -1,5 +1,13 @@ """ -This is test module for properies. +This is test module for properties. + +>>> r = properties.ret_type() +>>> r.i = 22.5 +>>> r.i +22.5 +>>> c = properties.crash_me() +>>> c.i.i +42.5 >>> X = properties.X