Skip to content

Commit eedc88b

Browse files
committed
Bug fixes in property handling
[SVN r21429]
1 parent 1102fec commit eedc88b

File tree

4 files changed

+99
-29
lines changed

4 files changed

+99
-29
lines changed

include/boost/python/class.hpp

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -127,23 +127,24 @@ namespace detail
127127
register_wrapper_class_impl((Held*)0, (T*)0, 0);
128128
}
129129

130-
# ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
131130
template <class T>
132131
struct is_data_member_pointer
133132
: mpl::and_<
134133
is_member_pointer<T>
135134
, mpl::not_<is_member_function_pointer<T> >
136135
>
137136
{};
138-
# define BOOST_PYTHON_DATA_MEMBER_HELPER , detail::is_data_member_pointer<D>()
137+
138+
# ifdef BOOST_PYTHON_NO_MEMBER_POINTER_ORDERING
139+
# define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , detail::is_data_member_pointer<D>()
139140
# define BOOST_PYTHON_YES_DATA_MEMBER , mpl::true_
140141
# define BOOST_PYTHON_NO_DATA_MEMBER , mpl::false_
141142
# elif defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
142-
# define BOOST_PYTHON_DATA_MEMBER_HELPER , 0
143+
# define BOOST_PYTHON_DATA_MEMBER_HELPER(D) , 0
143144
# define BOOST_PYTHON_YES_DATA_MEMBER , int
144145
# define BOOST_PYTHON_NO_DATA_MEMBER , ...
145146
# else
146-
# define BOOST_PYTHON_DATA_MEMBER_HELPER
147+
# define BOOST_PYTHON_DATA_MEMBER_HELPER(D)
147148
# define BOOST_PYTHON_YES_DATA_MEMBER
148149
# define BOOST_PYTHON_NO_DATA_MEMBER
149150
# endif
@@ -337,39 +338,39 @@ class class_ : public objects::class_base
337338
template <class D>
338339
self& def_readonly(char const* name, D const& d)
339340
{
340-
return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER);
341+
return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D));
341342
}
342343

343344
template <class D>
344345
self& def_readwrite(char const* name, D const& d)
345346
{
346-
return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER);
347+
return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D));
347348
}
348349

349350
template <class D>
350351
self& def_readonly(char const* name, D& d)
351352
{
352-
return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER);
353+
return this->def_readonly_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D));
353354
}
354355

355356
template <class D>
356357
self& def_readwrite(char const* name, D& d)
357358
{
358-
return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER);
359+
return this->def_readwrite_impl(name, d BOOST_PYTHON_DATA_MEMBER_HELPER(D));
359360
}
360361

361362
// Property creation
362363
template <class Get>
363364
self& add_property(char const* name, Get fget)
364365
{
365-
base::add_property(name, make_fn(fget));
366+
base::add_property(name, this->make_getter(fget));
366367
return *this;
367368
}
368369

369370
template <class Get, class Set>
370371
self& add_property(char const* name, Get fget, Set fset)
371372
{
372-
base::add_property(name, make_fn(fget), make_fn(fset));
373+
base::add_property(name, this->make_getter(fget), this->make_setter(fset));
373374
return *this;
374375
}
375376

@@ -415,25 +416,55 @@ class class_ : public objects::class_base
415416
}
416417
private: // helper functions
417418

418-
419419
// Builds a method for this class around the given [member]
420420
// function pointer or object, appropriately adjusting the type of
421421
// the first signature argument so that if f is a member of a
422422
// (possibly not wrapped) base class of T, an lvalue argument of
423423
// type T will be required.
424424
//
425-
// @group make_fn {
425+
// @group PropertyHelpers {
426+
template <class F>
427+
object make_getter(F f)
428+
{
429+
typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
430+
431+
return this->make_fn_impl(
432+
f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
433+
);
434+
}
435+
436+
template <class F>
437+
object make_setter(F f)
438+
{
439+
typedef typename api::is_object_operators<F>::type is_obj_or_proxy;
440+
441+
return this->make_fn_impl(
442+
f, is_obj_or_proxy(), (int*)0, detail::is_data_member_pointer<F>()
443+
);
444+
}
445+
426446
template <class F>
427-
object make_fn(F const& f)
447+
object make_fn_impl(F const& f, mpl::false_, void*, mpl::false_)
428448
{
429-
return make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
449+
return python::make_function(f, default_call_policies(), detail::get_signature(f, (T*)0));
430450
}
431451

432-
object
433-
# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
434-
const&
435-
# endif
436-
make_fn(object const& x)
452+
template <class D, class B>
453+
object make_fn_impl(D B::*pm_, mpl::false_, char*, mpl::true_)
454+
{
455+
D T::*pm = pm_;
456+
return python::make_getter(pm);
457+
}
458+
459+
template <class D, class B>
460+
object make_fn_impl(D B::*pm_, mpl::false_, int*, mpl::true_)
461+
{
462+
D T::*pm = pm_;
463+
return python::make_setter(pm);
464+
}
465+
466+
template <class F>
467+
object make_fn_impl(F const& x, mpl::true_, void*, mpl::false_)
437468
{
438469
return x;
439470
}
@@ -443,30 +474,28 @@ class class_ : public objects::class_base
443474
self& def_readonly_impl(
444475
char const* name, D B::*pm_ BOOST_PYTHON_YES_DATA_MEMBER)
445476
{
446-
D T::*pm = pm_;
447-
return this->add_property(name, make_getter(pm));
477+
return this->add_property(name, pm_);
448478
}
449479

450480
template <class D, class B>
451481
self& def_readwrite_impl(
452482
char const* name, D B::*pm_ BOOST_PYTHON_YES_DATA_MEMBER)
453483
{
454-
D T::*pm = pm_;
455-
return this->add_property(name, make_getter(pm), make_setter(pm));
484+
return this->add_property(name, pm_, pm_);
456485
}
457486

458487
template <class D>
459488
self& def_readonly_impl(
460489
char const* name, D& d BOOST_PYTHON_NO_DATA_MEMBER)
461490
{
462-
return this->add_static_property(name, make_getter(d));
491+
return this->add_static_property(name, python::make_getter(d));
463492
}
464493

465494
template <class D>
466495
self& def_readwrite_impl(
467496
char const* name, D& d BOOST_PYTHON_NO_DATA_MEMBER)
468497
{
469-
return this->add_static_property(name, make_getter(d), make_setter(d));
498+
return this->add_static_property(name, python::make_getter(d), python::make_setter(d));
470499
}
471500

472501
inline void register_() const;

include/boost/python/object_operators.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
namespace boost { namespace python { namespace api {
1919

20-
# if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE)
21-
2220
template <class X>
2321
char is_object_operators_helper(object_operators<X> const*);
2422

@@ -27,7 +25,7 @@ no_type is_object_operators_helper(...);
2725

2826
template <class X> X* make_ptr();
2927

30-
template <class L, class R>
28+
template <class L, class R = L>
3129
struct is_object_operators
3230
{
3331
enum {
@@ -40,6 +38,7 @@ struct is_object_operators
4038
typedef mpl::bool_<value> type;
4139
};
4240

41+
# if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE)
4342
template <class L, class R, class T>
4443
struct enable_binary
4544
: boost::iterators::enable_if<is_object_operators<L,R>, T>

test/properties.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@
22

33
using namespace boost::python;
44

5+
namespace test {
6+
7+
// Hmm. return_internal_reference<>() wants to wrap a real class.
8+
class ret_type
9+
{
10+
public:
11+
ret_type() : i(42.5) {}
12+
double i;
13+
};
14+
15+
class crash_me
16+
{
17+
private:
18+
ret_type i;
19+
public:
20+
ret_type& get_i() { return i; }
21+
};
22+
23+
}
24+
525
struct X
626
{
727
X( int value ) : m_value( value )
@@ -55,6 +75,20 @@ BOOST_PYTHON_MODULE(properties_ext)
5575
make_setter( &X::s_count, return_by_internal_reference_t() ) )
5676
//defining class property using a global function
5777
.add_static_property( "instance_count_injected", &get_X_instance_count );
78+
79+
80+
class_< test::ret_type>( "ret_type")
81+
.add_property( "i", &test::ret_type::i, &test::ret_type::i)
82+
;
83+
84+
class_< test::crash_me> crash_me_wrapper( "crash_me");
85+
86+
crash_me_wrapper
87+
.def( "get_i", &test::crash_me::get_i , return_internal_reference<>())
88+
;
89+
90+
crash_me_wrapper.add_property( "i", crash_me_wrapper.attr("get_i"));
91+
5892
}
5993

6094
#include "module_tail.cpp"

test/properties.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
"""
2-
This is test module for properies.
2+
This is test module for properties.
3+
4+
>>> r = properties.ret_type()
5+
>>> r.i = 22.5
6+
>>> r.i
7+
22.5
8+
>>> c = properties.crash_me()
9+
>>> c.i.i
10+
42.5
311
412
>>> X = properties.X
513

0 commit comments

Comments
 (0)