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