1 /////////////////////////////////////////////////////////////////////////////// 2 /// \file decltype.hpp 3 /// Contains definition the BOOST_PROTO_DECLTYPE_() macro and assorted helpers 4 // 5 // Copyright 2008 Eric Niebler. Distributed under the Boost 6 // Software License, Version 1.0. (See accompanying file 7 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 9 #ifndef BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 10 #define BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 11 12 #include <boost/config.hpp> 13 #include <boost/detail/workaround.hpp> 14 #include <boost/get_pointer.hpp> 15 #include <boost/preprocessor/cat.hpp> 16 #include <boost/preprocessor/repetition/enum_params.hpp> 17 #include <boost/preprocessor/repetition/enum_trailing_params.hpp> 18 #include <boost/preprocessor/repetition/enum_binary_params.hpp> 19 #include <boost/preprocessor/repetition/repeat.hpp> 20 #include <boost/preprocessor/repetition/repeat_from_to.hpp> 21 #include <boost/preprocessor/iteration/local.hpp> 22 #include <boost/mpl/if.hpp> 23 #include <boost/mpl/eval_if.hpp> 24 #include <boost/mpl/identity.hpp> 25 #include <boost/type_traits/is_class.hpp> 26 #include <boost/type_traits/remove_reference.hpp> 27 #include <boost/type_traits/is_pointer.hpp> 28 #include <boost/type_traits/is_function.hpp> 29 #include <boost/type_traits/is_member_object_pointer.hpp> 30 #include <boost/type_traits/add_const.hpp> 31 #include <boost/type_traits/add_reference.hpp> 32 #include <boost/typeof/typeof.hpp> 33 #include <boost/utility/addressof.hpp> 34 #include <boost/utility/result_of.hpp> 35 #include <boost/utility/enable_if.hpp> 36 #include <boost/proto/proto_fwd.hpp> 37 #include <boost/proto/detail/any.hpp> 38 39 #if defined(_MSC_VER) 40 # pragma warning(push) 41 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined 42 #endif 43 44 // We're STILL using Boost.Typeof on MSVC even for msvc-11.0 because of this bug: 45 // https://connect.microsoft.com/VisualStudio/feedback/details/765392/decltype-of-a-pointer-to-member-operator-gets-ref-qualification-wrong 46 #if !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700)) 47 # define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) typedef decltype((EXPR)) TYPE; 48 #else 49 # define BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(NESTED, EXPR) \ 50 BOOST_TYPEOF_NESTED_TYPEDEF_TPL(BOOST_PP_CAT(nested_and_hidden_, NESTED), EXPR) \ 51 static int const BOOST_PP_CAT(sz, NESTED) = sizeof(boost::proto::detail::check_reference(EXPR));\ 52 struct NESTED \ 53 : boost::mpl::if_c< \ 54 1 == BOOST_PP_CAT(sz, NESTED) \ 55 , typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type & \ 56 , typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type \ 57 > \ 58 {}; 59 # define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) \ 60 BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(BOOST_PP_CAT(nested_, TYPE), (EXPR)) \ 61 typedef typename BOOST_PP_CAT(nested_, TYPE)::type TYPE; 62 #endif 63 64 namespace boost { namespace proto 65 { 66 namespace detail 67 { 68 //////////////////////////////////////////////////////////////////////////////////////////// 69 template<typename T> 70 struct as_mutable 71 { 72 typedef T &type; 73 }; 74 75 template<typename T> 76 struct as_mutable<T &> 77 { 78 typedef T &type; 79 }; 80 81 template<typename T> 82 struct as_mutable<T const &> 83 { 84 typedef T &type; 85 }; 86 87 //////////////////////////////////////////////////////////////////////////////////////////// 88 template<typename T> 89 T make(); 90 91 //////////////////////////////////////////////////////////////////////////////////////////// 92 template<typename T> 93 typename as_mutable<T>::type make_mutable(); 94 95 //////////////////////////////////////////////////////////////////////////////////////////// 96 template<typename T> 97 struct subscript_wrapper 98 : T 99 { 100 using T::operator[]; 101 102 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) 103 any operator[](any const volatile &) const volatile; 104 #else 105 any operator[](any const &) const volatile; 106 #endif 107 }; 108 109 //////////////////////////////////////////////////////////////////////////////////////////// 110 template<typename T> 111 struct as_subscriptable 112 { 113 typedef 114 typename mpl::if_c< 115 is_class<T>::value 116 , subscript_wrapper<T> 117 , T 118 >::type 119 type; 120 }; 121 122 template<typename T> 123 struct as_subscriptable<T const> 124 { 125 typedef 126 typename mpl::if_c< 127 is_class<T>::value 128 , subscript_wrapper<T> const 129 , T const 130 >::type 131 type; 132 }; 133 134 template<typename T> 135 struct as_subscriptable<T &> 136 { 137 typedef 138 typename mpl::if_c< 139 is_class<T>::value 140 , subscript_wrapper<T> & 141 , T & 142 >::type 143 type; 144 }; 145 146 template<typename T> 147 struct as_subscriptable<T const &> 148 { 149 typedef 150 typename mpl::if_c< 151 is_class<T>::value 152 , subscript_wrapper<T> const & 153 , T const & 154 >::type 155 type; 156 }; 157 158 //////////////////////////////////////////////////////////////////////////////////////////// 159 template<typename T> 160 typename as_subscriptable<T>::type make_subscriptable(); 161 162 //////////////////////////////////////////////////////////////////////////////////////////// 163 template<typename T> 164 char check_reference(T &); 165 166 template<typename T> 167 char (&check_reference(T const &))[2]; 168 169 namespace has_get_pointerns 170 { 171 using boost::get_pointer; 172 void *(&get_pointer(...))[2]; 173 174 //////////////////////////////////////////////////////////////////////////////////////////// 175 template<typename T> 176 struct has_get_pointer 177 { 178 static const bool value = sizeof(void *) == sizeof(get_pointer(make<T &>())); 179 typedef mpl::bool_<value> type; 180 }; 181 } 182 183 using has_get_pointerns::has_get_pointer; 184 185 //////////////////////////////////////////////////////////////////////////////////////////// 186 template<typename T> 187 struct class_member_traits; 188 189 template<typename T, typename U> 190 struct class_member_traits<T U::*> 191 { 192 typedef U class_type; 193 typedef T result_type; 194 }; 195 196 // Other specializations are generated by the preprocessor 197 #include <boost/proto/detail/class_member_traits.hpp> 198 199 //////////////////////////////////////////////////////////////////////////////////////////// 200 template<typename T> lvalue(T & t)201 T &lvalue(T &t) 202 { 203 return t; 204 } 205 206 template<typename T> lvalue(T const & t)207 T const &lvalue(T const &t) 208 { 209 return t; 210 } 211 212 //////////////////////////////////////////////////////////////////////////////////////////// 213 template<typename U, typename V, typename T> proto_get_pointer(T & t,V *,U *)214 U *proto_get_pointer(T &t, V *, U *) 215 { 216 return boost::addressof(t); 217 } 218 219 template<typename U, typename V, typename T> proto_get_pointer(T & t,V *,U const *)220 U const *proto_get_pointer(T &t, V *, U const *) 221 { 222 return boost::addressof(t); 223 } 224 225 template<typename U, typename V, typename T> proto_get_pointer(T & t,V *,...)226 V *proto_get_pointer(T &t, V *, ...) 227 { 228 return get_pointer(t); 229 } 230 231 //////////////////////////////////////////////////////////////////////////////////////////// 232 #define BOOST_PROTO_USE_GET_POINTER() \ 233 using namespace boost::proto::detail::get_pointerns \ 234 /**/ 235 236 #define BOOST_PROTO_GET_POINTER(Type, Obj) \ 237 boost::proto::detail::proto_get_pointer<Type>( \ 238 boost::proto::detail::lvalue(Obj) \ 239 , (true ? 0 : get_pointer(Obj)) \ 240 , (true ? 0 : boost::addressof(boost::proto::detail::lvalue(Obj))) \ 241 ) \ 242 /**/ 243 244 //////////////////////////////////////////////////////////////////////////////////////////// 245 namespace get_pointerns 246 { 247 using boost::get_pointer; 248 249 template<typename T> 250 typename disable_if_c<has_get_pointer<T>::value, T *>::type get_pointer(T & t)251 get_pointer(T &t) 252 { 253 return boost::addressof(t); 254 } 255 256 template<typename T> 257 typename disable_if_c<has_get_pointer<T>::value, T const *>::type get_pointer(T const & t)258 get_pointer(T const &t) 259 { 260 return boost::addressof(t); 261 } 262 263 char test_ptr_to_const(void *); 264 char (&test_ptr_to_const(void const *))[2]; 265 266 template<typename U> char test_V_is_a_U(U *); 267 template<typename U> char test_V_is_a_U(U const *); 268 template<typename U> char (&test_V_is_a_U(...))[2]; 269 270 //////////////////////////////////////////////////////////////////////////////////////////// 271 // result_of_ is a wrapper around boost::result_of that also handles "invocations" of 272 // member object pointers. 273 template<typename T, typename Void = void> 274 struct result_of_ 275 : BOOST_PROTO_RESULT_OF<T> 276 {}; 277 278 template<typename T, typename U, typename V> 279 struct result_of_<T U::*(V), typename enable_if_c<is_member_object_pointer<T U::*>::value>::type> 280 { 281 static const bool is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U<U>(&lvalue(make<V>()))); 282 static const bool is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make<V>()))); 283 284 // If V is not a U, then it is a (smart) pointer and we can always return an lvalue. 285 // Otherwise, we can only return an lvalue if we are given one. 286 typedef 287 typename mpl::eval_if_c< 288 (is_V_a_smart_ptr || is_reference<V>::value) 289 , mpl::eval_if_c< 290 is_ptr_to_const 291 , add_reference<typename add_const<T>::type> 292 , add_reference<T> 293 > 294 , mpl::identity<T> 295 >::type 296 type; 297 }; 298 299 //////////////////////////////////////////////////////////////////////////////////////////// 300 template< 301 typename T 302 , typename U 303 , bool IsMemPtr = is_member_object_pointer< 304 typename remove_reference<U>::type 305 >::value 306 > 307 struct mem_ptr_fun 308 { 309 BOOST_PROTO_DECLTYPE_( 310 proto::detail::make_mutable<T>() ->* proto::detail::make<U>() 311 , result_type 312 ) 313 operator ()boost::proto::detail::get_pointerns::mem_ptr_fun314 result_type operator()( 315 typename add_reference<typename add_const<T>::type>::type t 316 , typename add_reference<typename add_const<U>::type>::type u 317 ) const 318 { 319 return t ->* u; 320 } 321 }; 322 323 //////////////////////////////////////////////////////////////////////////////////////////// 324 template<typename T, typename U> 325 struct mem_ptr_fun<T, U, true> 326 { 327 typedef 328 typename class_member_traits< 329 typename uncvref<U>::type 330 >::class_type 331 V; 332 333 BOOST_PROTO_DECLTYPE_( BOOST_PROTO_GET_POINTERboost::proto::detail::get_pointerns::mem_ptr_fun334 BOOST_PROTO_GET_POINTER(V, proto::detail::make_mutable<T>()) ->* proto::detail::make<U>() 335 , result_type 336 ) 337 338 result_type operator()( 339 typename add_reference<typename add_const<T>::type>::type t 340 , U u 341 ) const 342 { 343 return BOOST_PROTO_GET_POINTER(V, t) ->* u; 344 } 345 }; 346 } 347 348 using get_pointerns::result_of_; 349 using get_pointerns::mem_ptr_fun; 350 351 //////////////////////////////////////////////////////////////////////////////////////////// 352 template<typename A0, typename A1> 353 struct comma_result 354 { 355 BOOST_PROTO_DECLTYPE_((proto::detail::make<A0>(), proto::detail::make<A1>()), type) 356 }; 357 358 template<typename A0> 359 struct comma_result<A0, void> 360 { 361 typedef void type; 362 }; 363 364 template<typename A1> 365 struct comma_result<void, A1> 366 { 367 typedef A1 type; 368 }; 369 370 template<> 371 struct comma_result<void, void> 372 { 373 typedef void type; 374 }; 375 376 //////////////////////////////////////////////////////////////////////////////////////////// 377 // normalize a function type for use with boost::result_of 378 template<typename T, typename U = T> 379 struct result_of_fixup 380 : mpl::if_c<is_function<T>::value, T *, U> 381 {}; 382 383 template<typename T, typename U> 384 struct result_of_fixup<T &, U> 385 : result_of_fixup<T, T> 386 {}; 387 388 template<typename T, typename U> 389 struct result_of_fixup<T const &, U> 390 : result_of_fixup<T, T> 391 {}; 392 393 template<typename T, typename U> 394 struct result_of_fixup<T *, U> 395 : result_of_fixup<T, U> 396 {}; 397 398 template<typename R, typename T, typename U> 399 struct result_of_fixup<R T::*, U> 400 { 401 typedef R T::*type; 402 }; 403 404 template<typename T, typename U> 405 struct result_of_fixup<T const, U> 406 : result_of_fixup<T, U> 407 {}; 408 409 //// Tests for result_of_fixup 410 //struct bar {}; 411 //BOOST_MPL_ASSERT((is_same<bar, result_of_fixup<bar>::type>)); 412 //BOOST_MPL_ASSERT((is_same<bar const, result_of_fixup<bar const>::type>)); 413 //BOOST_MPL_ASSERT((is_same<bar, result_of_fixup<bar &>::type>)); 414 //BOOST_MPL_ASSERT((is_same<bar const, result_of_fixup<bar const &>::type>)); 415 //BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(*)()>::type>)); 416 //BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(* const)()>::type>)); 417 //BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(* const &)()>::type>)); 418 //BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(&)()>::type>)); 419 420 template<typename T, typename PMF> 421 struct memfun 422 { 423 typedef typename uncvref<PMF>::type pmf_type; 424 typedef typename class_member_traits<pmf_type>::class_type V; 425 typedef typename class_member_traits<pmf_type>::result_type result_type; 426 memfunboost::proto::detail::memfun427 memfun(T t, pmf_type p) 428 : obj(t) 429 , pmf(p) 430 {} 431 operator ()boost::proto::detail::memfun432 result_type operator()() const 433 { 434 BOOST_PROTO_USE_GET_POINTER(); 435 return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(); 436 } 437 438 // Other overloads generated by the preprocessor 439 #include <boost/proto/detail/memfun_funop.hpp> 440 441 private: 442 T obj; 443 pmf_type pmf; 444 }; 445 446 } // namespace detail 447 }} 448 449 #if defined(_MSC_VER) 450 # pragma warning(pop) 451 #endif 452 453 #endif 454