Skip to content

Commit 0ad3bfd

Browse files
committed
Finally fixed polymorphism issues
[SVN r16435]
1 parent fb7c450 commit 0ad3bfd

10 files changed

Lines changed: 319 additions & 145 deletions

File tree

include/boost/python/class.hpp

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,43 @@
88

99
# include <boost/python/class_fwd.hpp>
1010
# include <boost/python/object/class.hpp>
11-
# include <boost/python/bases.hpp>
1211

12+
# include <boost/python/bases.hpp>
1313
# include <boost/python/object.hpp>
14-
1514
# include <boost/python/type_id.hpp>
16-
# include <boost/python/object/class_converters.hpp>
15+
# include <boost/python/data_members.hpp>
16+
# include <boost/python/make_function.hpp>
17+
# include <boost/python/signature.hpp>
18+
# include <boost/python/init.hpp>
19+
# include <boost/python/args_fwd.hpp>
20+
1721
# include <boost/type_traits/ice.hpp>
18-
# include <boost/type_traits/same_traits.hpp>
22+
# include <boost/type_traits/is_same.hpp>
23+
# include <boost/type_traits/is_convertible.hpp>
24+
# include <boost/type_traits/is_member_function_pointer.hpp>
25+
# include <boost/type_traits/is_polymorphic.hpp>
26+
1927
# include <boost/mpl/size.hpp>
2028
# include <boost/mpl/for_each.hpp>
2129
# include <boost/mpl/bool_c.hpp>
30+
# include <boost/mpl/logical/not.hpp>
31+
2232
# include <boost/python/object/select_holder.hpp>
2333
# include <boost/python/object/class_wrapper.hpp>
2434
# include <boost/python/object/make_instance.hpp>
25-
# include <boost/python/data_members.hpp>
26-
# include <boost/utility.hpp>
2735
# include <boost/python/object/pickle_support.hpp>
28-
# include <boost/python/make_function.hpp>
2936
# include <boost/python/object/add_to_namespace.hpp>
30-
# include <boost/python/signature.hpp>
31-
# include <boost/python/init.hpp>
32-
# include <boost/python/args_fwd.hpp>
37+
# include <boost/python/object/class_converters.hpp>
3338

3439
# include <boost/python/detail/string_literal.hpp>
35-
3640
# include <boost/python/detail/overloads_fwd.hpp>
3741
# include <boost/python/detail/operator_id.hpp>
3842
# include <boost/python/detail/member_function_cast.hpp>
3943
# include <boost/python/detail/def_helper.hpp>
4044
# include <boost/python/detail/force_instantiate.hpp>
4145

46+
# include <boost/utility.hpp>
47+
4248
namespace boost { namespace python {
4349

4450
enum no_init_t { no_init };
@@ -89,6 +95,54 @@ namespace detail
8995
{
9096
SelectHolder::register_();
9197
}
98+
99+
namespace error
100+
{
101+
//
102+
// A meta-assertion mechanism which prints nice error messages and
103+
// backtraces on lots of compilers. Usage:
104+
//
105+
// assertion<C>::failed
106+
//
107+
// where C is an MPL metafunction class
108+
//
109+
110+
template <class C> struct assertion_failed { };
111+
template <class C> struct assertion_ok { typedef C failed; };
112+
113+
template <class C>
114+
struct assertion
115+
: mpl::if_<C, assertion_ok<C>, assertion_failed<C> >::type
116+
{};
117+
118+
//
119+
// Checks for validity of arguments used to define virtual
120+
// functions with default implementations.
121+
//
122+
123+
template <class Default>
124+
void not_a_derived_class_member(Default) {}
125+
126+
template <class T, class Fn>
127+
struct virtual_function_default
128+
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
129+
: assertion<is_polymorphic<T> >::failed
130+
, assertion<is_member_function_pointer<Fn> >::failed
131+
# endif
132+
{
133+
template <class Default>
134+
static void
135+
must_be_derived_class_member(Default const&)
136+
{
137+
typedef typename assertion<mpl::logical_not<is_same<Default,Fn> > >::failed test0;
138+
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
139+
typedef typename assertion<is_polymorphic<T> >::failed test1;
140+
typedef typename assertion<is_member_function_pointer<Fn> >::failed test2;
141+
# endif
142+
not_a_derived_class_member<Default>(Fn());
143+
}
144+
};
145+
}
92146
}
93147

94148
// This is the primary mechanism through which users will expose
@@ -313,6 +367,22 @@ class class_ : public objects::class_base
313367
// things which are already wrapped into callable python::object
314368
// instances and everything else.
315369
//
370+
template <class F, class A1>
371+
inline void def_impl(
372+
char const* name
373+
, F f
374+
, detail::def_helper<A1> const& helper
375+
, object const*)
376+
{
377+
// It's too late to specify anything other than docstrings, if
378+
// the callable object is already wrapped.
379+
BOOST_STATIC_ASSERT(
380+
(is_same<char const*,A1>::value
381+
|| detail::is_string_literal<A1>::value));
382+
383+
objects::add_to_namespace(*this, name, f, helper.doc());
384+
}
385+
316386
template <class Fn, class Helper>
317387
inline void def_impl(
318388
char const* name
@@ -327,24 +397,36 @@ class class_ : public objects::class_base
327397
detail::member_function_cast<T,Fn>::stage1(fn).stage2((T*)0).stage3(fn)
328398
, helper.policies(), helper.keywords())
329399
, helper.doc());
400+
401+
this->def_default(name, fn, helper, mpl::bool_c<Helper::has_default_implementation>());
330402
}
331403

332-
template <class F, class A1>
333-
inline void def_impl(
404+
//
405+
// These two overloads handle the definition of default
406+
// implementation overloads for virtual functions. The second one
407+
// handles the case where no default implementation was specified.
408+
//
409+
template <class Fn, class Helper>
410+
inline void def_default(
334411
char const* name
335-
, F f
336-
, detail::def_helper<A1> const& helper
337-
, object const*)
412+
, Fn fn
413+
, Helper const& helper
414+
, mpl::bool_c<true>)
338415
{
339-
// It's too late to specify anything other than docstrings, if
340-
// the callable object is already wrapped.
341-
BOOST_STATIC_ASSERT(
342-
(is_same<char const*,A1>::value
343-
|| detail::is_string_literal<A1>::value));
344-
345-
objects::add_to_namespace(*this, name, f, helper.doc());
416+
detail::error::virtual_function_default<T,Fn>::must_be_derived_class_member(
417+
helper.default_implementation());
418+
419+
objects::add_to_namespace(
420+
*this, name,
421+
make_function(
422+
helper.default_implementation(), helper.policies(), helper.keywords())
423+
);
346424
}
347-
425+
426+
template <class Fn, class Helper>
427+
inline void def_default(char const*, Fn, Helper const&, mpl::bool_c<false>)
428+
{ }
429+
348430
//
349431
// These two overloads discriminate between def() as applied to
350432
// regular functions and def() as applied to the result of

include/boost/python/detail/caller.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ struct select_result_converter
5656
};
5757

5858

59-
template <unsigned> struct caller_gen;
59+
template <unsigned> struct caller_arity;
6060

6161
# define BOOST_PYTHON_NEXT(init,name,n) \
6262
typedef BOOST_PP_IF(n,typename BOOST_PP_CAT(name,BOOST_PP_DEC(n)) ::next, init) name##n;
@@ -81,8 +81,8 @@ template <unsigned> struct caller_gen;
8181
template <class F, class ConverterGenerators, class CallPolicies, class Sig>
8282
struct caller_base_select
8383
{
84-
enum { n_arguments = mpl::size<Sig>::value - 1 };
85-
typedef typename caller_gen<n_arguments>::template impl<F,ConverterGenerators,CallPolicies,Sig> type;
84+
enum { arity = mpl::size<Sig>::value - 1 };
85+
typedef typename caller_arity<arity>::template impl<F,ConverterGenerators,CallPolicies,Sig> type;
8686
};
8787

8888
// A function object type which wraps C++ objects as Python callable
@@ -131,7 +131,7 @@ struct caller
131131
# define N BOOST_PP_ITERATION()
132132

133133
template <>
134-
struct caller_gen<N>
134+
struct caller_arity<N>
135135
{
136136
template <class F, class ConverterGenerators, class Policies, class Sig>
137137
struct impl

include/boost/python/detail/def_helper.hpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,11 @@ namespace detail
9797
template <class Tuple>
9898
struct doc_extract
9999
: tuple_extract<
100-
Tuple,
101-
mpl::logical_not<
100+
Tuple
101+
, mpl::logical_not<
102102
mpl::logical_or<
103103
is_reference_to_class<mpl::_1>
104-
, is_reference_to_function_pointer<mpl::_1 >
105-
, is_reference_to_function<mpl::_1 >
104+
, is_reference_to_member_function_pointer<mpl::_1 >
106105
>
107106
>
108107
>
@@ -118,8 +117,8 @@ namespace detail
118117
template <class Tuple>
119118
struct policy_extract
120119
: tuple_extract<
121-
Tuple,
122-
mpl::logical_and<
120+
Tuple
121+
, mpl::logical_and<
123122
mpl::logical_not<is_same<not_specified const&,mpl::_1> >
124123
, is_reference_to_class<mpl::_1 >
125124
, mpl::logical_not<is_reference_to_keywords<mpl::_1 > >
@@ -131,12 +130,9 @@ namespace detail
131130
template <class Tuple>
132131
struct default_implementation_extract
133132
: tuple_extract<
134-
Tuple,
135-
mpl::logical_or<
136-
is_reference_to_function_pointer<mpl::_1 >
137-
, is_reference_to_function<mpl::_1 >
133+
Tuple
134+
, is_reference_to_member_function_pointer<mpl::_1 >
138135
>
139-
>
140136
{
141137
};
142138

@@ -161,8 +157,8 @@ namespace detail
161157
, default_call_policies
162158
, keywords<0>
163159
, char const*
164-
, void(*)() // A function pointer type which is never an
165-
// appropriate default implementation
160+
, void(not_specified::*)() // A function pointer type which is never an
161+
// appropriate default implementation
166162
> all_t;
167163

168164
// Constructors; these initialize an member of the tuple type
@@ -172,15 +168,16 @@ namespace detail
172168
def_helper(T1 const& a1, T2 const& a2, T3 const& a3) : m_all(a1,a2,a3,m_nil) {}
173169
def_helper(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4) : m_all(a1,a2,a3,a4) {}
174170

175-
private: // type
171+
private: // types
176172
typedef typename default_implementation_extract<all_t>::result_type default_implementation_t;
173+
174+
public: // Constants which can be used for static assertions.
177175

178-
public: // Constant which can be used for static assertions. Users
179-
// must not supply a default implementation for non-class
180-
// methods.
176+
// Users must not supply a default implementation for non-class
177+
// methods.
181178
BOOST_STATIC_CONSTANT(
182179
bool, has_default_implementation = (
183-
!is_same<default_implementation_t, void(*)()>::value));
180+
!is_same<default_implementation_t, void(not_specified::*)()>::value));
184181

185182
public: // Extractor functions which pull the appropriate value out
186183
// of the tuple
@@ -201,7 +198,7 @@ namespace detail
201198

202199
default_implementation_t default_implementation() const
203200
{
204-
return policy_extract<all_t>::extract(m_all);
201+
return default_implementation_extract<all_t>::extract(m_all);
205202
}
206203

207204
private: // data members

include/boost/python/detail/indirect_traits.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,22 @@ typename is_const_help<V>::type reference_to_const_helper(V&);
302302
outer_no_type
303303
reference_to_const_helper(...);
304304

305+
struct true_helper1
306+
{
307+
template <class T>
308+
struct apply
309+
{
310+
static T t;
311+
BOOST_STATIC_CONSTANT(
312+
bool, value
313+
= sizeof(reference_to_const_helper(t)) == sizeof(inner_yes_type));
314+
};
315+
};
316+
305317
template <bool ref = true>
306-
struct is_reference_to_const_helper1
318+
struct is_reference_to_const_helper1 : true_helper1
307319
{
320+
# if 0
308321
template <class T>
309322
struct apply
310323
{
@@ -313,6 +326,7 @@ struct is_reference_to_const_helper1
313326
bool, value
314327
= sizeof(reference_to_const_helper(t)) == sizeof(inner_yes_type));
315328
};
329+
# endif
316330
};
317331

318332
template <>

include/boost/python/detail/invoke.hpp

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
# include <boost/python/detail/wrap_python.hpp>
1212
# include <boost/python/detail/preprocessor.hpp>
1313
# include <boost/python/detail/none.hpp>
14-
# include <boost/python/detail/this_arg_from_python.hpp>
1514

1615
# include <boost/type_traits/is_member_function_pointer.hpp>
1716

@@ -52,7 +51,6 @@ template <class T> struct is_defaulted_virtual_fn;
5251
// Tag types describing invocation methods
5352
struct fn_tag {};
5453
struct mem_fn_tag {};
55-
struct virtual_fn_tag {};
5654

5755
// A metafunction returning the appropriate tag type for invoking an
5856
// object of type T.
@@ -61,11 +59,7 @@ struct invoke_tag
6159
: mpl::if_<
6260
is_member_function_pointer<T>
6361
, mem_fn_tag
64-
, typename mpl::if_<
65-
is_defaulted_virtual_fn<T>
66-
, virtual_fn_tag
67-
, fn_tag
68-
>::type
62+
, fn_tag
6963
>
7064
{};
7165

@@ -106,25 +100,6 @@ inline PyObject* invoke(mem_fn_tag, void_result_to_python, F& f, TC& tc BOOST_PP
106100
return none();
107101
}
108102

109-
template <class RC, class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
110-
inline PyObject* invoke(virtual_fn_tag, RC*, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
111-
{
112-
return RC()(
113-
tc.use_default()
114-
? f.default_impl(tc() BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT))
115-
: (tc().*f.dispatch)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac, () BOOST_PP_INTERCEPT)) );
116-
}
117-
118-
template <class F, class TC BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class AC)>
119-
inline PyObject* invoke(virtual_fn_tag, void_result_to_python, F& f, TC& tc BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, AC, & ac) )
120-
{
121-
if (tc.use_default())
122-
f.default_impl(tc() BOOST_PP_ENUM_TRAILING_BINARY_PARAMS_Z(1, N, ac,()BOOST_PP_INTERCEPT));
123-
else
124-
(tc().*f.dispatch)(BOOST_PP_ENUM_BINARY_PARAMS_Z(1, N, ac,()BOOST_PP_INTERCEPT));
125-
return none();
126-
}
127-
128103
# undef N
129104

130105
#endif // BOOST_PP_IS_ITERATING

0 commit comments

Comments
 (0)