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