1 | |
2 | // (C) Copyright Tobias Schwinger |
3 | // |
4 | // Use modification and distribution are subject to the boost Software License, |
5 | // Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). |
6 | |
7 | //------------------------------------------------------------------------------ |
8 | |
9 | #ifndef BOOST_FT_COMPONENTS_HPP_INCLUDED |
10 | #define BOOST_FT_COMPONENTS_HPP_INCLUDED |
11 | |
12 | #include <cstddef> |
13 | |
14 | #include <boost/config.hpp> |
15 | |
16 | #include <boost/detail/workaround.hpp> |
17 | #include <boost/mpl/aux_/lambda_support.hpp> |
18 | |
19 | #include <boost/type_traits/integral_constant.hpp> |
20 | |
21 | #include <boost/mpl/if.hpp> |
22 | #include <boost/mpl/integral_c.hpp> |
23 | #include <boost/mpl/vector/vector0.hpp> |
24 | |
25 | #if BOOST_WORKAROUND(__BORLANDC__, <= 0x565) |
26 | # include <boost/type_traits/remove_cv.hpp> |
27 | |
28 | # include <boost/mpl/identity.hpp> |
29 | # include <boost/mpl/bitand.hpp> |
30 | # include <boost/mpl/vector/vector10.hpp> |
31 | # include <boost/mpl/front.hpp> |
32 | # include <boost/mpl/begin.hpp> |
33 | # include <boost/mpl/advance.hpp> |
34 | # include <boost/mpl/iterator_range.hpp> |
35 | # include <boost/mpl/joint_view.hpp> |
36 | # include <boost/mpl/equal_to.hpp> |
37 | # include <boost/mpl/copy.hpp> |
38 | # include <boost/mpl/front_inserter.hpp> |
39 | |
40 | # include <boost/function_types/detail/classifier.hpp> |
41 | #endif |
42 | |
43 | #ifndef BOOST_FT_NO_CV_FUNC_SUPPORT |
44 | # include <boost/mpl/remove.hpp> |
45 | #endif |
46 | |
47 | #include <boost/function_types/config/config.hpp> |
48 | |
49 | # if BOOST_FT_MAX_ARITY < 10 |
50 | # include <boost/mpl/vector/vector10.hpp> |
51 | # elif BOOST_FT_MAX_ARITY < 20 |
52 | # include <boost/mpl/vector/vector20.hpp> |
53 | # elif BOOST_FT_MAX_ARITY < 30 |
54 | # include <boost/mpl/vector/vector30.hpp> |
55 | # elif BOOST_FT_MAX_ARITY < 40 |
56 | # include <boost/mpl/vector/vector40.hpp> |
57 | # elif BOOST_FT_MAX_ARITY < 50 |
58 | # include <boost/mpl/vector/vector50.hpp> |
59 | # endif |
60 | |
61 | #include <boost/function_types/detail/class_transform.hpp> |
62 | #include <boost/function_types/property_tags.hpp> |
63 | |
64 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
65 | |
66 | namespace boost |
67 | { |
68 | namespace function_types |
69 | { |
70 | |
71 | using mpl::placeholders::_; |
72 | |
73 | template< typename T, typename ClassTypeTransform = add_reference<_> > |
74 | struct components; |
75 | |
76 | namespace detail |
77 | { |
78 | template<typename T, typename L> struct components_impl; |
79 | #if BOOST_WORKAROUND(__BORLANDC__, <= 0x565) |
80 | template<typename T, typename OrigT, typename L> struct components_bcc; |
81 | #endif |
82 | } |
83 | |
84 | template<typename T, typename ClassTypeTransform> |
85 | struct components |
86 | #if !BOOST_WORKAROUND(__BORLANDC__, <= 0x565) |
87 | : detail::components_impl<T, ClassTypeTransform> |
88 | #else |
89 | : detail::components_bcc<typename remove_cv<T>::type,T, |
90 | ClassTypeTransform> |
91 | #endif |
92 | { |
93 | typedef components<T,ClassTypeTransform> type; |
94 | |
95 | BOOST_MPL_AUX_LAMBDA_SUPPORT(2,components,(T,ClassTypeTransform)) |
96 | }; |
97 | |
98 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
99 | |
100 | namespace detail { |
101 | |
102 | struct components_mpl_sequence_tag; |
103 | |
104 | struct components_non_func_base |
105 | { |
106 | typedef mpl::vector0<> types; |
107 | typedef void function_arity; |
108 | |
109 | typedef detail::constant<0> bits; |
110 | typedef detail::constant<0> mask; |
111 | |
112 | typedef components_mpl_sequence_tag tag; |
113 | }; |
114 | |
115 | template |
116 | < typename Components |
117 | , typename IfTagged |
118 | , typename ThenTag |
119 | , typename DefaultBase = components_non_func_base |
120 | > |
121 | struct retagged_if |
122 | : mpl::if_ |
123 | < detail::represents_impl<Components, IfTagged> |
124 | , detail::changed_tag<Components,IfTagged,ThenTag> |
125 | , DefaultBase |
126 | >::type |
127 | { }; |
128 | |
129 | // We detect plain function types and function references as function |
130 | // pointers by recursive instantiation of components_impl. |
131 | // The third specialization of components_impl makes sure the recursion |
132 | // terminates (when adding pointers). |
133 | template<typename T, typename L> |
134 | struct components_impl |
135 | : detail::retagged_if |
136 | < detail::components_impl<T*,L> |
137 | , pointer_tag, /* --> */ function_tag > |
138 | { }; |
139 | template<typename T, typename L> |
140 | struct components_impl<T&, L> |
141 | : detail::retagged_if |
142 | < detail::components_impl<T*,L> |
143 | , pointer_tag, /* --> */ reference_tag > |
144 | { }; |
145 | |
146 | #if !BOOST_FT_NO_CV_FUNC_SUPPORT |
147 | // Retry the type with a member pointer attached to detect cv functions |
148 | class a_class; |
149 | |
150 | template<typename Base, typename T, typename L> |
151 | struct cv_func_base |
152 | : detail::retagged_if<Base,member_pointer_tag,function_tag> |
153 | { |
154 | typedef typename |
155 | mpl::remove |
156 | < typename Base::types |
157 | , typename detail::class_transform<a_class,L>::type>::type |
158 | types; |
159 | }; |
160 | |
161 | template<typename T, typename L> |
162 | struct components_impl<T*, L> |
163 | : mpl::if_ |
164 | < detail::represents_impl< detail::components_impl<T a_class::*, L> |
165 | , member_pointer_tag > |
166 | , detail::cv_func_base< detail::components_impl<T a_class::*, L>, T, L> |
167 | , components_non_func_base |
168 | >::type |
169 | { }; |
170 | |
171 | template<typename T, typename L> |
172 | struct components_impl<T a_class::*, L> |
173 | : components_non_func_base |
174 | { }; |
175 | #else |
176 | template<typename T, typename L> |
177 | struct components_impl<T*, L> |
178 | : components_non_func_base |
179 | { }; |
180 | #endif |
181 | |
182 | template<typename T, typename L> |
183 | struct components_impl<T* const, L> |
184 | : components_impl<T*,L> |
185 | { }; |
186 | |
187 | template<typename T, typename L> |
188 | struct components_impl<T* volatile, L> |
189 | : components_impl<T*,L> |
190 | { }; |
191 | |
192 | template<typename T, typename L> |
193 | struct components_impl<T* const volatile, L> |
194 | : components_impl<T*,L> |
195 | { }; |
196 | |
197 | template<typename T, typename L> |
198 | struct components_impl<T const, L> |
199 | : components_impl<T,L> |
200 | { }; |
201 | |
202 | template<typename T, typename L> |
203 | struct components_impl<T volatile, L> |
204 | : components_impl<T,L> |
205 | { }; |
206 | |
207 | template<typename T, typename L> |
208 | struct components_impl<T const volatile, L> |
209 | : components_impl<T,L> |
210 | { }; |
211 | |
212 | |
213 | template<typename T, class C> |
214 | struct member_obj_ptr_result |
215 | { typedef T & type; }; |
216 | |
217 | template<typename T, class C> |
218 | struct member_obj_ptr_result<T, C const> |
219 | { typedef T const & type; }; |
220 | |
221 | template<typename T, class C> |
222 | struct member_obj_ptr_result<T, C volatile> |
223 | { typedef T volatile & type; }; |
224 | |
225 | template<typename T, class C> |
226 | struct member_obj_ptr_result<T, C const volatile> |
227 | { typedef T const volatile & type; }; |
228 | |
229 | template<typename T, class C> |
230 | struct member_obj_ptr_result<T &, C> |
231 | { typedef T & type; }; |
232 | |
233 | template<typename T, class C> |
234 | struct member_obj_ptr_result<T &, C const> |
235 | { typedef T & type; }; |
236 | |
237 | template<typename T, class C> |
238 | struct member_obj_ptr_result<T &, C volatile> |
239 | { typedef T & type; }; |
240 | |
241 | template<typename T, class C> |
242 | struct member_obj_ptr_result<T &, C const volatile> |
243 | { typedef T & type; }; |
244 | |
245 | template<typename T, class C, typename L> |
246 | struct member_obj_ptr_components |
247 | : member_object_pointer_base |
248 | { |
249 | typedef function_types::components<T C::*, L> type; |
250 | typedef components_mpl_sequence_tag tag; |
251 | |
252 | typedef mpl::integral_c<std::size_t,1> function_arity; |
253 | |
254 | typedef mpl::vector2< typename detail::member_obj_ptr_result<T,C>::type, |
255 | typename detail::class_transform<C,L>::type > types; |
256 | }; |
257 | |
258 | #if !BOOST_WORKAROUND(__BORLANDC__, <= 0x565) |
259 | # define BOOST_FT_variations BOOST_FT_pointer|BOOST_FT_member_pointer |
260 | |
261 | template<typename T, class C, typename L> |
262 | struct components_impl<T C::*, L> |
263 | : member_obj_ptr_components<T,C,L> |
264 | { }; |
265 | |
266 | #else |
267 | # define BOOST_FT_variations BOOST_FT_pointer |
268 | |
269 | // This workaround removes the member pointer from the type to allow |
270 | // detection of member function pointers with BCC. |
271 | template<typename T, typename C, typename L> |
272 | struct components_impl<T C::*, L> |
273 | : detail::retagged_if |
274 | < detail::components_impl<typename boost::remove_cv<T>::type *, L> |
275 | , pointer_tag, /* --> */ member_function_pointer_tag |
276 | , member_obj_ptr_components<T,C,L> > |
277 | { }; |
278 | |
279 | // BCC lets us test the cv-qualification of a function type by template |
280 | // partial specialization - so we use this bug feature to find out the |
281 | // member function's cv-qualification (unfortunately there are some |
282 | // invisible modifiers that impose some limitations on these types even if |
283 | // we remove the qualifiers, So we cannot exploit the same bug to make the |
284 | // library work for cv-qualified function types). |
285 | template<typename T> struct encode_cv |
286 | { typedef char (& type)[1]; BOOST_STATIC_CONSTANT(std::size_t, value = 1); }; |
287 | template<typename T> struct encode_cv<T const *> |
288 | { typedef char (& type)[2]; BOOST_STATIC_CONSTANT(std::size_t, value = 2); }; |
289 | template<typename T> struct encode_cv<T volatile *> |
290 | { typedef char (& type)[3]; BOOST_STATIC_CONSTANT(std::size_t, value = 3); }; |
291 | template<typename T> struct encode_cv<T const volatile *> |
292 | { typedef char (& type)[4]; BOOST_STATIC_CONSTANT(std::size_t, value = 4); }; |
293 | |
294 | // For member function pointers we have to use a function template (partial |
295 | // template specialization for a member pointer drops the cv qualification |
296 | // of the function type). |
297 | template<typename T, typename C> |
298 | typename encode_cv<T *>::type mfp_cv_tester(T C::*); |
299 | |
300 | template<typename T> struct encode_mfp_cv |
301 | { |
302 | BOOST_STATIC_CONSTANT(std::size_t, value = |
303 | sizeof(detail::mfp_cv_tester((T)0L))); |
304 | }; |
305 | |
306 | // Associate bits with the CV codes above. |
307 | template<std::size_t> struct cv_tag_mfp_impl; |
308 | |
309 | template<typename T> struct cv_tag_mfp |
310 | : detail::cv_tag_mfp_impl |
311 | < ::boost::function_types::detail::encode_mfp_cv<T>::value > |
312 | { }; |
313 | |
314 | template<> struct cv_tag_mfp_impl<1> : non_cv { }; |
315 | template<> struct cv_tag_mfp_impl<2> : const_non_volatile { }; |
316 | template<> struct cv_tag_mfp_impl<3> : volatile_non_const { }; |
317 | template<> struct cv_tag_mfp_impl<4> : cv_qualified { }; |
318 | |
319 | // Metafunction to decode the cv code and apply it to a type. |
320 | // We add a pointer, because otherwise cv-qualifiers won't stick (another bug). |
321 | template<typename T, std::size_t CV> struct decode_cv; |
322 | |
323 | template<typename T> struct decode_cv<T,1> : mpl::identity<T *> {}; |
324 | template<typename T> struct decode_cv<T,2> : mpl::identity<T const *> {}; |
325 | template<typename T> struct decode_cv<T,3> : mpl::identity<T volatile *> {}; |
326 | template<typename T> struct decode_cv<T,4> |
327 | : mpl::identity<T const volatile *> {}; |
328 | |
329 | // The class type transformation comes after adding cv-qualifiers. We have |
330 | // wrap it to remove the pointer added in decode_cv_impl. |
331 | template<typename T, typename L> struct bcc_class_transform_impl; |
332 | template<typename T, typename L> struct bcc_class_transform_impl<T *, L> |
333 | : class_transform<T,L> |
334 | { }; |
335 | |
336 | template<typename T, typename D, typename L> struct bcc_class_transform |
337 | : bcc_class_transform_impl |
338 | < typename decode_cv |
339 | < T |
340 | , ::boost::function_types::detail::encode_mfp_cv<D>::value |
341 | >::type |
342 | , L |
343 | > |
344 | { }; |
345 | |
346 | // After extracting the member pointee from the type the class type is still |
347 | // in the type (somewhere -- you won't see with RTTI, that is) and that type |
348 | // is flagged unusable and *not* identical to the nonmember function type. |
349 | // We can, however, decompose this type via components_impl but surprisingly |
350 | // a pointer to the const qualified class type pops up again as the first |
351 | // parameter type. |
352 | // We have to replace this type with the properly cv-qualified and |
353 | // transformed class type, integrate the cv qualification into the bits. |
354 | template<typename Base, typename MFP, typename OrigT, typename L> |
355 | struct mfp_components; |
356 | |
357 | |
358 | template<typename Base, typename T, typename C, typename OrigT, typename L> |
359 | struct mfp_components<Base,T C::*,OrigT,L> |
360 | { |
361 | private: |
362 | typedef typename mpl::front<typename Base::types>::type result_type; |
363 | typedef typename detail::bcc_class_transform<C,OrigT,L>::type class_type; |
364 | |
365 | typedef mpl::vector2<result_type, class_type> result_and_class_type; |
366 | |
367 | typedef typename |
368 | mpl::advance |
369 | < typename mpl::begin<typename Base::types>::type |
370 | , typename mpl::if_ |
371 | < mpl::equal_to< typename detail::classifier<OrigT>::function_arity |
372 | , typename Base::function_arity > |
373 | , mpl::integral_c<int,2> , mpl::integral_c<int,1> |
374 | >::type |
375 | >::type |
376 | from; |
377 | typedef typename mpl::end<typename Base::types>::type to; |
378 | |
379 | typedef mpl::iterator_range<from,to> param_types; |
380 | |
381 | typedef mpl::joint_view< result_and_class_type, param_types> types_view; |
382 | public: |
383 | |
384 | typedef typename |
385 | mpl::reverse_copy<types_view, mpl::front_inserter< mpl::vector0<> > >::type |
386 | types; |
387 | |
388 | typedef typename |
389 | function_types::tag< Base, detail::cv_tag_mfp<OrigT> >::bits |
390 | bits; |
391 | |
392 | typedef typename Base::mask mask; |
393 | |
394 | typedef typename detail::classifier<OrigT>::function_arity function_arity; |
395 | |
396 | typedef components_mpl_sequence_tag tag; |
397 | }; |
398 | |
399 | // Now put it all together: detect cv-qualification of function types and do |
400 | // the weird transformations above for member function pointers. |
401 | template<typename T, typename OrigT, typename L> |
402 | struct components_bcc |
403 | : mpl::if_ |
404 | < detail::represents_impl< detail::components_impl<T,L> |
405 | , member_function_pointer_tag> |
406 | , detail::mfp_components<detail::components_impl<T,L>,T,OrigT,L> |
407 | , detail::components_impl<T,L> |
408 | >::type |
409 | { }; |
410 | |
411 | #endif // end of BORLAND WORKAROUND |
412 | |
413 | #define BOOST_FT_al_path boost/function_types/detail/components_impl |
414 | #include <boost/function_types/detail/pp_loop.hpp> |
415 | |
416 | } } // namespace function_types::detail |
417 | |
418 | } // namespace ::boost |
419 | |
420 | #include <boost/function_types/detail/components_as_mpl_sequence.hpp> |
421 | #include <boost/function_types/detail/retag_default_cc.hpp> |
422 | |
423 | #endif |
424 | |
425 | |