77# define CLASS_DWA200216_HPP
88
99# include < boost/python/class_fwd.hpp>
10+ # include < boost/python/bases.hpp>
11+ # include < boost/python/args.hpp>
1012# include < boost/python/reference.hpp>
1113# include < boost/python/object/class.hpp>
12- # include < boost/python/object/value_holder_fwd.hpp>
1314# include < boost/python/converter/type_id.hpp>
1415# include < boost/python/detail/wrap_function.hpp>
1516# include < boost/python/detail/member_function_cast.hpp>
16- # include < boost/mpl/type_list.hpp>
1717# include < boost/python/object/class_converters.hpp>
18+ # include < boost/type_traits/ice.hpp>
19+ # include < boost/type_traits/same_traits.hpp>
1820# include < boost/mpl/size.hpp>
1921# include < boost/mpl/for_each.hpp>
20- # include < boost/python/detail/type_list.hpp>
21-
22- namespace // put some convenience classes into the unnamed namespace for the user
23- {
24- // A type list for specifying bases
25- template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename B, ::boost::mpl::null_argument) >
26- struct bases : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(B) >::type
27- {};
28-
29- // A type list for specifying arguments
30- template < BOOST_MPL_LIST_DEFAULT_PARAMETERS(typename A, ::boost::mpl::null_argument) >
31- struct args : ::boost::mpl::type_list< BOOST_MPL_LIST_PARAMETERS(A) >::type
32- {};
33- }
22+ # include < boost/mpl/bool_t.hpp>
23+ # include < boost/python/object/select_holder.hpp>
24+ # include < boost/python/object/class_wrapper.hpp>
25+ # include < boost/utility.hpp>
3426
3527namespace boost { namespace python {
3628
3729namespace detail
3830{
39- // This is an mpl BinaryMetaFunction object with a runtime behavior,
40- // which is to write the id of the type which is passed as its 2nd
41- // compile-time argument into the iterator pointed to by its runtime
42- // argument
43- struct write_type_id
31+ struct write_type_id ;
32+
33+ template <class T , class Prev = detail::not_specified>
34+ struct select_held_type ;
35+
36+ template <class T1 , class T2 , class T3 >
37+ struct has_noncopyable ;
38+
39+ // Register a to_python converter for a class T, depending on the
40+ // type of the first (tag) argument. The 2nd argument is a pointer
41+ // to the type of holder that must be created. The 3rd argument is a
42+ // reference to the Python type object to be created.
43+ template <class T , class Holder >
44+ static inline void register_copy_constructor (mpl::bool_t <true > const &, Holder*, ref const & obj, T* = 0 )
4445 {
45- // The first argument is Ignored because mpl::for_each is still
46- // currently an accumulate (reduce) implementation.
47- template <class Ignored , class T > struct apply
48- {
49- // also an artifact of accumulate-based for_each
50- typedef void type;
46+ objects::class_wrapper<T,Holder> x (obj);
47+ }
5148
52- // Here's the runtime behavior
53- static void execute (converter::undecorated_type_id_t ** p)
54- {
55- *(*p)++ = converter::undecorated_type_id<T>();
56- }
57- };
58- };
49+ // Tag dispatched to have no effect.
50+ template <class T , class Holder >
51+ static inline void register_copy_constructor (mpl::bool_t <false > const &, Holder*, ref const &, T* = 0 )
52+ {
53+ }
5954}
6055
6156//
@@ -64,27 +59,24 @@ namespace detail
6459// This is the primary mechanism through which users will expose
6560// C++ classes to Python. The three template arguments are:
6661//
67- // T - The class being exposed to Python
68- //
69- // Bases - An MPL sequence of base classes
70- //
71- // HolderGenerator -
72- // An optional type generator for the "holder" which
73- // maintains the C++ object inside the Python instance. The
74- // default just holds the object "by-value", but other
75- // holders can be substituted which will hold the C++ object
76- // by smart pointer, for example.
77- //
7862template <
7963 class T // class being wrapped
80- , class Bases
81- , class HolderGenerator
64+ , class X1 // = detail::not_specified
65+ , class X2 // = detail::not_specified
66+ , class X3 // = detail::not_specified
8267 >
8368class class_ : private objects ::class_base
8469{
85- typedef class_<T,Bases,HolderGenerator> self;
70+ typedef class_<T,X1,X2,X3> self;
71+ BOOST_STATIC_CONSTANT (bool , is_copyable = (!detail::has_noncopyable<X1,X2,X3>::value));
72+
73+ typedef typename detail::select_held_type<
74+ X1, typename detail::select_held_type<
75+ X2, typename detail::select_held_type<
76+ X3
77+ >::type>::type>::type held_type;
78+
8679 public:
87-
8880 // Automatically derive the class name - only works on some
8981 // compilers because type_info::name is sometimes mangled (gcc)
9082 class_ ();
@@ -130,7 +122,12 @@ class class_ : private objects::class_base
130122 template <class Args >
131123 self& def_init (Args const &)
132124 {
133- def (" __init__" , make_constructor<T,Args,HolderGenerator>());
125+ def (" __init__" ,
126+ make_constructor<Args>(
127+ // Using runtime type selection works around a CWPro7 bug.
128+ objects::select_holder<T,held_type>((held_type*)0 ).get ()
129+ )
130+ );
134131 return *this ;
135132 }
136133
@@ -147,6 +144,12 @@ class class_ : private objects::class_base
147144 private: // types
148145 typedef objects::class_id class_id;
149146
147+ typedef typename detail::select_bases<X1
148+ , typename detail::select_bases<X2
149+ , typename boost::python::detail::select_bases<X3>::type
150+ >::type
151+ >::type bases;
152+
150153 // A helper class which will contain an array of id objects to be
151154 // passed to the base class constructor
152155 struct id_vector
@@ -159,50 +162,97 @@ class class_ : private objects::class_base
159162
160163 // Write the rest of the elements into succeeding positions.
161164 class_id* p = ids + 1 ;
162- mpl::for_each<Bases , void , detail::write_type_id>::execute (&p);
165+ mpl::for_each<bases , void , detail::write_type_id>::execute (&p);
163166 }
164167
165168 BOOST_STATIC_CONSTANT (
166- std::size_t , size = mpl::size<Bases >::value + 1 );
169+ std::size_t , size = mpl::size<bases >::value + 1 );
167170 class_id ids[size];
168171 };
169-
170- private: // helper functions
171- void initialize_converters ();
172172};
173173
174174
175175//
176176// implementations
177177//
178- template <class T , class Bases , class HolderGenerator >
179- inline class_<T, Bases, HolderGenerator >::class_()
178+ template <class T , class X1 , class X2 , class X3 >
179+ inline class_<T,X1,X2,X3 >::class_()
180180 : class_base(typeid (T).name(), id_vector::size, id_vector().ids)
181181{
182- // Bring the class converters into existence. This static object
183- // will survive until the shared library this module lives in is
184- // unloaded (that doesn't happen until Python terminates).
185- static objects::class_converters<T,Bases> converters (object ());
182+ // register converters
183+ objects::register_class_from_python<T,bases>();
184+
185+ detail::register_copy_constructor<T>(
186+ mpl::bool_t <is_copyable>()
187+ , objects::select_holder<T,held_type>((held_type*)0 ).get ()
188+ , this ->object ());
186189}
187190
188- template <class T , class Bases , class HolderGenerator >
189- inline class_<T, Bases, HolderGenerator >::class_(char const * name)
191+ template <class T , class X1 , class X2 , class X3 >
192+ inline class_<T,X1,X2,X3 >::class_(char const * name)
190193 : class_base(name, id_vector::size, id_vector().ids)
191194{
192- // Bring the class converters into existence. This static object
193- // will survive until the shared library this module lives in is
194- // unloaded (that doesn't happen until Python terminates).
195- static objects::class_converters<T,Bases> converters (object ());
195+ // register converters
196+ objects::register_class_from_python<T,bases>();
197+
198+ detail::register_copy_constructor<T>(
199+ mpl::bool_t <is_copyable>()
200+ , objects::select_holder<T,held_type>((held_type*)0 ).get ()
201+ , this ->object ());
196202}
197203
198- template <class T , class Bases , class HolderGenerator >
199- inline ref class_<T, Bases, HolderGenerator >::object() const
204+ template <class T , class X1 , class X2 , class X3 >
205+ inline ref class_<T,X1,X2,X3 >::object() const
200206{
201207 typedef objects::class_base base;
202208
203209 return this ->base ::object ();
204210}
205211
212+ namespace detail
213+ {
214+ // This is an mpl BinaryMetaFunction object with a runtime behavior,
215+ // which is to write the id of the type which is passed as its 2nd
216+ // compile-time argument into the iterator pointed to by its runtime
217+ // argument
218+ struct write_type_id
219+ {
220+ // The first argument is Ignored because mpl::for_each is still
221+ // currently an accumulate (reduce) implementation.
222+ template <class Ignored , class T > struct apply
223+ {
224+ // also an artifact of accumulate-based for_each
225+ typedef void type;
226+
227+ // Here's the runtime behavior
228+ static void execute (converter::undecorated_type_id_t ** p)
229+ {
230+ *(*p)++ = converter::undecorated_type_id<T>();
231+ }
232+ };
233+ };
234+
235+
236+ template <class T1 , class T2 , class T3 >
237+ struct has_noncopyable
238+ : type_traits::ice_or<
239+ is_same<T1,noncopyable>::value
240+ , is_same<T2,noncopyable>::value
241+ , is_same<T3,noncopyable>::value>
242+ {};
243+
244+
245+ template <class T , class Prev >
246+ struct select_held_type
247+ : mpl::select_type<
248+ !(specifies_bases<T>::value | is_same<T,noncopyable>::value)
249+ , T
250+ , Prev
251+ >
252+ {
253+ };
254+ }
255+
206256}} // namespace boost::python
207257
208258#endif // CLASS_DWA200216_HPP
0 commit comments