make.hpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. ///////////////////////////////////////////////////////////////////////////////
  2. /// \file make.hpp
  3. /// Contains definition of the make<> transform.
  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_TRANSFORM_MAKE_HPP_EAN_12_02_2007
  9. #define BOOST_PROTO_TRANSFORM_MAKE_HPP_EAN_12_02_2007
  10. #include <boost/detail/workaround.hpp>
  11. #include <boost/preprocessor/repetition/enum.hpp>
  12. #include <boost/preprocessor/repetition/enum_params.hpp>
  13. #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
  14. #include <boost/preprocessor/repetition/enum_binary_params.hpp>
  15. #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
  16. #include <boost/preprocessor/repetition/repeat_from_to.hpp>
  17. #include <boost/preprocessor/facilities/intercept.hpp>
  18. #include <boost/preprocessor/cat.hpp>
  19. #include <boost/preprocessor/iteration/iterate.hpp>
  20. #include <boost/preprocessor/selection/max.hpp>
  21. #include <boost/preprocessor/arithmetic/inc.hpp>
  22. #include <boost/mpl/and.hpp>
  23. #include <boost/mpl/aux_/has_type.hpp>
  24. #include <boost/proto/detail/template_arity.hpp>
  25. #include <boost/utility/result_of.hpp>
  26. #include <boost/proto/proto_fwd.hpp>
  27. #include <boost/proto/traits.hpp>
  28. #include <boost/proto/args.hpp>
  29. #include <boost/proto/transform/impl.hpp>
  30. #include <boost/proto/transform/detail/pack.hpp>
  31. #include <boost/proto/detail/as_lvalue.hpp>
  32. #include <boost/proto/detail/ignore_unused.hpp>
  33. #if defined(_MSC_VER)
  34. # pragma warning(push)
  35. # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
  36. #endif
  37. namespace boost { namespace proto
  38. {
  39. namespace detail
  40. {
  41. template<typename T>
  42. struct is_applyable
  43. : mpl::and_<is_callable<T>, is_transform<T> >
  44. {};
  45. template<typename T, bool HasType = mpl::aux::has_type<T>::value>
  46. struct nested_type
  47. {
  48. typedef typename T::type type;
  49. };
  50. template<typename T>
  51. struct nested_type<T, false>
  52. {
  53. typedef T type;
  54. };
  55. template<typename T, bool Applied>
  56. struct nested_type_if
  57. {
  58. typedef T type;
  59. static bool const applied = false;
  60. };
  61. template<typename T>
  62. struct nested_type_if<T, true>
  63. : nested_type<T>
  64. {
  65. static bool const applied = true;
  66. };
  67. template<
  68. typename R
  69. , typename Expr, typename State, typename Data
  70. BOOST_PROTO_TEMPLATE_ARITY_PARAM(long Arity = detail::template_arity<R>::value)
  71. >
  72. struct make_
  73. {
  74. typedef R type;
  75. static bool const applied = false;
  76. };
  77. template<
  78. typename R
  79. , typename Expr, typename State, typename Data
  80. , bool IsApplyable = is_applyable<R>::value
  81. >
  82. struct make_if_
  83. : make_<R, Expr, State, Data>
  84. {};
  85. template<typename R, typename Expr, typename State, typename Data>
  86. struct make_if_<R, Expr, State, Data, true>
  87. : uncvref<typename when<_, R>::template impl<Expr, State, Data>::result_type>
  88. {
  89. static bool const applied = true;
  90. };
  91. #if BOOST_WORKAROUND(__GNUC__, == 3) || (BOOST_WORKAROUND(__GNUC__, == 4) && __GNUC_MINOR__ == 0)
  92. // work around GCC bug
  93. template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data>
  94. struct make_if_<proto::expr<Tag, Args, N>, Expr, State, Data, false>
  95. {
  96. typedef proto::expr<Tag, Args, N> type;
  97. static bool const applied = false;
  98. };
  99. // work around GCC bug
  100. template<typename Tag, typename Args, long N, typename Expr, typename State, typename Data>
  101. struct make_if_<proto::basic_expr<Tag, Args, N>, Expr, State, Data, false>
  102. {
  103. typedef proto::basic_expr<Tag, Args, N> type;
  104. static bool const applied = false;
  105. };
  106. #endif
  107. template<typename Type, bool IsAggregate = detail::is_aggregate_<Type>::value>
  108. struct construct_
  109. {
  110. typedef Type result_type;
  111. BOOST_FORCEINLINE
  112. Type operator ()() const
  113. {
  114. return Type();
  115. }
  116. // Other overloads generated by the preprocessor
  117. #include <boost/proto/transform/detail/construct_funop.hpp>
  118. };
  119. template<typename Type>
  120. struct construct_<Type, true>
  121. {
  122. typedef Type result_type;
  123. BOOST_FORCEINLINE
  124. Type operator ()() const
  125. {
  126. return Type();
  127. }
  128. // Other overloads generated by the preprocessor
  129. #include <boost/proto/transform/detail/construct_pod_funop.hpp>
  130. };
  131. }
  132. /// \brief A PrimitiveTransform which prevents another PrimitiveTransform
  133. /// from being applied in an \c ObjectTransform.
  134. ///
  135. /// When building higher order transforms with <tt>make\<\></tt> or
  136. /// <tt>lazy\<\></tt>, you sometimes would like to build types that
  137. /// are parameterized with Proto transforms. In such lambda-style
  138. /// transforms, Proto will unhelpfully find all nested transforms
  139. /// and apply them, even if you don't want them to be applied. Consider
  140. /// the following transform, which will replace the \c _ in
  141. /// <tt>Bar<_>()</tt> with <tt>proto::terminal\<int\>::type</tt>:
  142. ///
  143. /// \code
  144. /// template<typename T>
  145. /// struct Bar
  146. /// {};
  147. ///
  148. /// struct Foo
  149. /// : proto::when<_, Bar<_>() >
  150. /// {};
  151. ///
  152. /// proto::terminal<int>::type i = {0};
  153. ///
  154. /// int main()
  155. /// {
  156. /// Foo()(i);
  157. /// std::cout << typeid(Foo()(i)).name() << std::endl;
  158. /// }
  159. /// \endcode
  160. ///
  161. /// If you actually wanted to default-construct an object of type
  162. /// <tt>Bar\<_\></tt>, you would have to protect the \c _ to prevent
  163. /// it from being applied. You can use <tt>proto::protect\<\></tt>
  164. /// as follows:
  165. ///
  166. /// \code
  167. /// // OK: replace anything with Bar<_>()
  168. /// struct Foo
  169. /// : proto::when<_, Bar<protect<_> >() >
  170. /// {};
  171. /// \endcode
  172. template<typename PrimitiveTransform>
  173. struct protect : transform<protect<PrimitiveTransform> >
  174. {
  175. template<typename, typename, typename>
  176. struct impl
  177. {
  178. typedef PrimitiveTransform result_type;
  179. };
  180. };
  181. /// \brief A PrimitiveTransform which computes a type by evaluating any
  182. /// nested transforms and then constructs an object of that type.
  183. ///
  184. /// The <tt>make\<\></tt> transform checks to see if \c Object is a template.
  185. /// If it is, the template type is disassembled to find nested transforms.
  186. /// Proto considers the following types to represent transforms:
  187. ///
  188. /// \li Function types
  189. /// \li Function pointer types
  190. /// \li Types for which <tt>proto::is_callable\< type \>::value</tt> is \c true
  191. ///
  192. /// <tt>boost::result_of\<make\<T\<X0,X1,...\> \>(Expr, State, Data)\>::type</tt>
  193. /// is evaluated as follows. For each \c X in <tt>X0,X1,...</tt>, do:
  194. ///
  195. /// \li If \c X is a template like <tt>U\<Y0,Y1,...\></tt>, then let <tt>X'</tt>
  196. /// be <tt>boost::result_of\<make\<U\<Y0,Y1,...\> \>(Expr, State, Data)\>::type</tt>
  197. /// (which evaluates this procedure recursively). Note whether any
  198. /// substitutions took place during this operation.
  199. /// \li Otherwise, if \c X is a transform, then let <tt>X'</tt> be
  200. /// <tt>boost::result_of\<when\<_, X\>(Expr, State, Data)\>::type</tt>.
  201. /// Note that a substitution took place.
  202. /// \li Otherwise, let <tt>X'</tt> be \c X, and note that no substitution
  203. /// took place.
  204. /// \li If any substitutions took place in any of the above steps and
  205. /// <tt>T\<X0',X1',...\></tt> has a nested <tt>::type</tt> typedef,
  206. /// the result type is <tt>T\<X0',X1',...\>::type</tt>.
  207. /// \li Otherwise, the result type is <tt>T\<X0',X1',...\></tt>.
  208. ///
  209. /// Note that <tt>when\<\></tt> is implemented in terms of <tt>call\<\></tt>
  210. /// and <tt>make\<\></tt>, so the above procedure is evaluated recursively.
  211. template<typename Object>
  212. struct make : transform<make<Object> >
  213. {
  214. template<typename Expr, typename State, typename Data>
  215. struct impl : transform_impl<Expr, State, Data>
  216. {
  217. typedef typename detail::make_if_<Object, Expr, State, Data>::type result_type;
  218. /// \return <tt>result_type()</tt>
  219. BOOST_FORCEINLINE
  220. result_type operator ()(
  221. typename impl::expr_param
  222. , typename impl::state_param
  223. , typename impl::data_param
  224. ) const
  225. {
  226. return result_type();
  227. }
  228. };
  229. };
  230. /// INTERNAL ONLY
  231. template<typename Fun>
  232. struct make<detail::msvc_fun_workaround<Fun> >
  233. : make<Fun>
  234. {};
  235. // Other specializations generated by the preprocessor.
  236. #include <boost/proto/transform/detail/make.hpp>
  237. #include <boost/proto/transform/detail/make_gcc_workaround.hpp>
  238. /// INTERNAL ONLY
  239. ///
  240. template<typename Object>
  241. struct is_callable<make<Object> >
  242. : mpl::true_
  243. {};
  244. /// INTERNAL ONLY
  245. ///
  246. template<typename PrimitiveTransform>
  247. struct is_callable<protect<PrimitiveTransform> >
  248. : mpl::true_
  249. {};
  250. }}
  251. #if defined(_MSC_VER)
  252. # pragma warning(pop)
  253. #endif
  254. #endif