| 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> |
| 201 | T &lvalue(T &t) |
| 202 | { |
| 203 | return t; |
| 204 | } |
| 205 | |
| 206 | template<typename T> |
| 207 | T const &lvalue(T const &t) |
| 208 | { |
| 209 | return t; |
| 210 | } |
| 211 | |
| 212 | //////////////////////////////////////////////////////////////////////////////////////////// |
| 213 | template<typename U, typename V, typename T> |
| 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> |
| 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> |
| 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 |
| 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 |
| 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 | |
| 314 | 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_( |
| 334 | 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 | |
| 427 | memfun(T t, pmf_type p) |
| 428 | : obj(t) |
| 429 | , pmf(p) |
| 430 | {} |
| 431 | |
| 432 | 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 | |