]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
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 | |
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 | |
243 | 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 |