decltype.hpp 16 KB

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