1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file operators.hpp |
3 | /// Contains all the overloaded operators that make it possible to build |
4 | /// Proto expression trees. |
5 | // |
6 | // Copyright 2008 Eric Niebler. Distributed under the Boost |
7 | // Software License, Version 1.0. (See accompanying file |
8 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
9 | |
10 | #ifndef BOOST_PROTO_OPERATORS_HPP_EAN_04_01_2005 |
11 | #define BOOST_PROTO_OPERATORS_HPP_EAN_04_01_2005 |
12 | |
13 | #include <boost/config.hpp> |
14 | #include <boost/preprocessor/punctuation/comma.hpp> |
15 | #include <boost/mpl/logical.hpp> |
16 | #include <boost/utility/enable_if.hpp> |
17 | #include <boost/proto/proto_fwd.hpp> |
18 | #include <boost/proto/tags.hpp> |
19 | #include <boost/proto/domain.hpp> |
20 | #include <boost/proto/matches.hpp> |
21 | #include <boost/proto/generate.hpp> |
22 | #include <boost/proto/make_expr.hpp> |
23 | |
24 | #if defined(_MSC_VER) |
25 | # pragma warning(push) |
26 | # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined |
27 | #endif |
28 | |
29 | namespace boost { namespace proto |
30 | { |
31 | namespace detail |
32 | { |
33 | template<typename MakeExpr, typename Grammar> |
34 | struct lazy_matches |
35 | : proto::matches<typename MakeExpr::type, Grammar> |
36 | {}; |
37 | |
38 | template<typename Domain, typename Grammar, typename Trait, typename Tag, typename Arg> |
39 | struct enable_unary |
40 | : boost::lazy_enable_if_c< |
41 | boost::mpl::and_< |
42 | Trait |
43 | , lazy_matches<result_of::make_expr<Tag, basic_default_domain, Arg>, Grammar> |
44 | >::value |
45 | , result_of::make_expr<Tag, Domain, Arg> |
46 | > |
47 | {}; |
48 | |
49 | template<typename Domain, typename Trait, typename Tag, typename Arg> |
50 | struct enable_unary<Domain, proto::_, Trait, Tag, Arg &> |
51 | : boost::lazy_enable_if_c< |
52 | Trait::value |
53 | , result_of::make_expr<Tag, Domain, Arg &> |
54 | > |
55 | {}; |
56 | |
57 | template<typename Trait, typename Tag, typename Arg> |
58 | struct enable_unary<deduce_domain, not_a_grammar, Trait, Tag, Arg &> |
59 | : enable_unary< |
60 | typename domain_of<Arg>::type |
61 | , typename domain_of<Arg>::type::proto_grammar |
62 | , Trait |
63 | , Tag |
64 | , Arg & |
65 | > |
66 | {}; |
67 | |
68 | template<typename Domain, typename Grammar, typename Trait, typename Tag, typename Left, typename Right> |
69 | struct enable_binary |
70 | : boost::lazy_enable_if_c< |
71 | boost::mpl::and_< |
72 | Trait |
73 | , lazy_matches<result_of::make_expr<Tag, basic_default_domain, Left, Right>, Grammar> |
74 | >::value |
75 | , result_of::make_expr<Tag, Domain, Left, Right> |
76 | > |
77 | {}; |
78 | |
79 | template<typename Domain, typename Trait, typename Tag, typename Left, typename Right> |
80 | struct enable_binary<Domain, proto::_, Trait, Tag, Left &, Right &> |
81 | : boost::lazy_enable_if_c< |
82 | Trait::value |
83 | , result_of::make_expr<Tag, Domain, Left &, Right &> |
84 | > |
85 | {}; |
86 | |
87 | template<typename Trait, typename Tag, typename Left, typename Right> |
88 | struct enable_binary<deduce_domain, not_a_grammar, Trait, Tag, Left &, Right &> |
89 | : enable_binary< |
90 | typename deduce_domain2<Left, Right>::type |
91 | , typename deduce_domain2<Left, Right>::type::proto_grammar |
92 | , Trait |
93 | , Tag |
94 | , Left & |
95 | , Right & |
96 | > |
97 | {}; |
98 | |
99 | } // detail |
100 | |
101 | #define BOOST_PROTO_UNARY_OP_IS_POSTFIX_0 |
102 | #define BOOST_PROTO_UNARY_OP_IS_POSTFIX_1 , int |
103 | |
104 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES |
105 | |
106 | #define BOOST_PROTO_DEFINE_UNARY_OPERATOR(OP, TAG, TRAIT, DOMAIN, POST) \ |
107 | BOOST_PROTO_PUSH_WARNINGS \ |
108 | \ |
109 | template<typename Arg> \ |
110 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
111 | typename boost::proto::detail::enable_unary< \ |
112 | DOMAIN \ |
113 | , DOMAIN::proto_grammar \ |
114 | , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg) \ |
115 | , TAG \ |
116 | , Arg & \ |
117 | >::type const \ |
118 | operator OP(Arg &arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST) \ |
119 | { \ |
120 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg &>()(arg); \ |
121 | } \ |
122 | \ |
123 | template<typename Arg> \ |
124 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
125 | typename boost::proto::detail::enable_unary< \ |
126 | DOMAIN \ |
127 | , DOMAIN::proto_grammar \ |
128 | , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg) \ |
129 | , TAG \ |
130 | , Arg const & \ |
131 | >::type const \ |
132 | operator OP(Arg const &arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST) \ |
133 | { \ |
134 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg const &>()(arg); \ |
135 | } \ |
136 | \ |
137 | BOOST_PROTO_POP_WARNINGS \ |
138 | /**/ |
139 | |
140 | #define BOOST_PROTO_DEFINE_BINARY_OPERATOR(OP, TAG, TRAIT, DOMAIN) \ |
141 | BOOST_PROTO_PUSH_WARNINGS \ |
142 | \ |
143 | template<typename Left, typename Right> \ |
144 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
145 | typename boost::proto::detail::enable_binary< \ |
146 | DOMAIN \ |
147 | , DOMAIN::proto_grammar \ |
148 | , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right) \ |
149 | , TAG \ |
150 | , Left & \ |
151 | , Right & \ |
152 | >::type const \ |
153 | operator OP(Left &left, Right &right) \ |
154 | { \ |
155 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Left &, Right &>()(left, right); \ |
156 | } \ |
157 | \ |
158 | template<typename Left, typename Right> \ |
159 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
160 | typename boost::proto::detail::enable_binary< \ |
161 | DOMAIN \ |
162 | , DOMAIN::proto_grammar \ |
163 | , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right) \ |
164 | , TAG \ |
165 | , Left & \ |
166 | , Right const & \ |
167 | >::type const \ |
168 | operator OP(Left &left, Right const &right) \ |
169 | { \ |
170 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Left &, Right const &>()(left, right); \ |
171 | } \ |
172 | \ |
173 | template<typename Left, typename Right> \ |
174 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
175 | typename boost::proto::detail::enable_binary< \ |
176 | DOMAIN \ |
177 | , DOMAIN::proto_grammar \ |
178 | , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right) \ |
179 | , TAG \ |
180 | , Left const & \ |
181 | , Right & \ |
182 | >::type const \ |
183 | operator OP(Left const &left, Right &right) \ |
184 | { \ |
185 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right &>()(left, right); \ |
186 | } \ |
187 | \ |
188 | template<typename Left, typename Right> \ |
189 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
190 | typename boost::proto::detail::enable_binary< \ |
191 | DOMAIN \ |
192 | , DOMAIN::proto_grammar \ |
193 | , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right) \ |
194 | , TAG \ |
195 | , Left const & \ |
196 | , Right const & \ |
197 | >::type const \ |
198 | operator OP(Left const &left, Right const &right) \ |
199 | { \ |
200 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right const &>()(left, right);\ |
201 | } \ |
202 | \ |
203 | BOOST_PROTO_POP_WARNINGS \ |
204 | /**/ |
205 | |
206 | #else |
207 | |
208 | #define BOOST_PROTO_DEFINE_UNARY_OPERATOR(OP, TAG, TRAIT, DOMAIN, POST) \ |
209 | template<typename Arg> \ |
210 | BOOST_PROTO_PUSH_WARNINGS \ |
211 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
212 | typename boost::proto::detail::enable_unary< \ |
213 | DOMAIN \ |
214 | , DOMAIN::proto_grammar \ |
215 | , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg) \ |
216 | , TAG \ |
217 | , Arg const & \ |
218 | >::type const \ |
219 | operator OP(Arg &&arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST) \ |
220 | { \ |
221 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg const &>()(arg); \ |
222 | } \ |
223 | BOOST_PROTO_POP_WARNINGS \ |
224 | /**/ |
225 | |
226 | #define BOOST_PROTO_DEFINE_BINARY_OPERATOR(OP, TAG, TRAIT, DOMAIN) \ |
227 | template<typename Left, typename Right> \ |
228 | BOOST_PROTO_PUSH_WARNINGS \ |
229 | BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE \ |
230 | typename boost::proto::detail::enable_binary< \ |
231 | DOMAIN \ |
232 | , DOMAIN::proto_grammar \ |
233 | , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right) \ |
234 | , TAG \ |
235 | , Left const & \ |
236 | , Right const & \ |
237 | >::type const \ |
238 | operator OP(Left &&left, Right &&right) \ |
239 | { \ |
240 | return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right const &>()(left, right);\ |
241 | } \ |
242 | BOOST_PROTO_POP_WARNINGS \ |
243 | /**/ |
244 | |
245 | #endif |
246 | |
247 | #define BOOST_PROTO_DEFINE_OPERATORS(TRAIT, DOMAIN) \ |
248 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(+, boost::proto::tag::unary_plus, TRAIT, DOMAIN, 0) \ |
249 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(-, boost::proto::tag::negate, TRAIT, DOMAIN, 0) \ |
250 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(*, boost::proto::tag::dereference, TRAIT, DOMAIN, 0) \ |
251 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(~, boost::proto::tag::complement, TRAIT, DOMAIN, 0) \ |
252 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(&, boost::proto::tag::address_of, TRAIT, DOMAIN, 0) \ |
253 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(!, boost::proto::tag::logical_not, TRAIT, DOMAIN, 0) \ |
254 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(++, boost::proto::tag::pre_inc, TRAIT, DOMAIN, 0) \ |
255 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(--, boost::proto::tag::pre_dec, TRAIT, DOMAIN, 0) \ |
256 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(++, boost::proto::tag::post_inc, TRAIT, DOMAIN, 1) \ |
257 | BOOST_PROTO_DEFINE_UNARY_OPERATOR(--, boost::proto::tag::post_dec, TRAIT, DOMAIN, 1) \ |
258 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(<<, boost::proto::tag::shift_left, TRAIT, DOMAIN) \ |
259 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(>>, boost::proto::tag::shift_right, TRAIT, DOMAIN) \ |
260 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(*, boost::proto::tag::multiplies, TRAIT, DOMAIN) \ |
261 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(/, boost::proto::tag::divides, TRAIT, DOMAIN) \ |
262 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(%, boost::proto::tag::modulus, TRAIT, DOMAIN) \ |
263 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(+, boost::proto::tag::plus, TRAIT, DOMAIN) \ |
264 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(-, boost::proto::tag::minus, TRAIT, DOMAIN) \ |
265 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(<, boost::proto::tag::less, TRAIT, DOMAIN) \ |
266 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(>, boost::proto::tag::greater, TRAIT, DOMAIN) \ |
267 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(<=, boost::proto::tag::less_equal, TRAIT, DOMAIN) \ |
268 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(>=, boost::proto::tag::greater_equal, TRAIT, DOMAIN) \ |
269 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(==, boost::proto::tag::equal_to, TRAIT, DOMAIN) \ |
270 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(!=, boost::proto::tag::not_equal_to, TRAIT, DOMAIN) \ |
271 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(||, boost::proto::tag::logical_or, TRAIT, DOMAIN) \ |
272 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(&&, boost::proto::tag::logical_and, TRAIT, DOMAIN) \ |
273 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(&, boost::proto::tag::bitwise_and, TRAIT, DOMAIN) \ |
274 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(|, boost::proto::tag::bitwise_or, TRAIT, DOMAIN) \ |
275 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(^, boost::proto::tag::bitwise_xor, TRAIT, DOMAIN) \ |
276 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(BOOST_PP_COMMA(), boost::proto::tag::comma, TRAIT, DOMAIN) \ |
277 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(->*, boost::proto::tag::mem_ptr, TRAIT, DOMAIN) \ |
278 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(<<=, boost::proto::tag::shift_left_assign, TRAIT, DOMAIN) \ |
279 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(>>=, boost::proto::tag::shift_right_assign, TRAIT, DOMAIN) \ |
280 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(*=, boost::proto::tag::multiplies_assign, TRAIT, DOMAIN) \ |
281 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(/=, boost::proto::tag::divides_assign, TRAIT, DOMAIN) \ |
282 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(%=, boost::proto::tag::modulus_assign, TRAIT, DOMAIN) \ |
283 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(+=, boost::proto::tag::plus_assign, TRAIT, DOMAIN) \ |
284 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(-=, boost::proto::tag::minus_assign, TRAIT, DOMAIN) \ |
285 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(&=, boost::proto::tag::bitwise_and_assign, TRAIT, DOMAIN) \ |
286 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(|=, boost::proto::tag::bitwise_or_assign, TRAIT, DOMAIN) \ |
287 | BOOST_PROTO_DEFINE_BINARY_OPERATOR(^=, boost::proto::tag::bitwise_xor_assign, TRAIT, DOMAIN) \ |
288 | /**/ |
289 | |
290 | // Extensions are a superset of Proto expressions |
291 | template<typename T> |
292 | struct is_extension |
293 | : is_expr<T> |
294 | {}; |
295 | |
296 | template<typename T> |
297 | struct is_extension<T &> |
298 | : is_expr<T> |
299 | {}; |
300 | |
301 | #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG) TRAIT<ARG> |
302 | #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT) boost::mpl::or_<TRAIT<LEFT>, TRAIT<RIGHT> > |
303 | |
304 | namespace exprns_ |
305 | { |
306 | // This defines all of Proto's built-in free operator overloads |
307 | BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain) |
308 | |
309 | // if_else, for the non-overloadable ternary conditional operator ?: |
310 | template<typename A0, typename A1, typename A2> |
311 | BOOST_FORCEINLINE |
312 | typename result_of::make_expr< |
313 | tag::if_else_ |
314 | , deduce_domain |
315 | , A0 const & |
316 | , A1 const & |
317 | , A2 const & |
318 | >::type const |
319 | if_else(A0 const &a0, A1 const &a1, A2 const &a2) |
320 | { |
321 | return proto::detail::make_expr_< |
322 | tag::if_else_ |
323 | , deduce_domain |
324 | , A0 const & |
325 | , A1 const & |
326 | , A2 const & |
327 | >()(a0, a1, a2); |
328 | } |
329 | } |
330 | |
331 | using exprns_::if_else; |
332 | |
333 | #undef BOOST_PROTO_APPLY_UNARY_ |
334 | #undef BOOST_PROTO_APPLY_BINARY_ |
335 | |
336 | // Redefine BOOST_PROTO_APPLY_UNARY_ and BOOST_PROTO_APPLY_BINARY_ so that end users |
337 | // can use BOOST_PROTO_DEFINE_OPERATORS to define Proto operator overloads that work |
338 | // with their own terminal types. |
339 | |
340 | #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES |
341 | |
342 | #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG) \ |
343 | boost::mpl::and_< \ |
344 | TRAIT<ARG> \ |
345 | , boost::mpl::not_<boost::proto::is_extension<ARG> > \ |
346 | > \ |
347 | /**/ |
348 | |
349 | #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT) \ |
350 | boost::mpl::and_< \ |
351 | boost::mpl::or_<TRAIT<LEFT>, TRAIT<RIGHT> > \ |
352 | , boost::mpl::not_< \ |
353 | boost::mpl::or_< \ |
354 | boost::proto::is_extension<LEFT> \ |
355 | , boost::proto::is_extension<RIGHT> \ |
356 | > \ |
357 | > \ |
358 | > \ |
359 | /**/ |
360 | |
361 | #else |
362 | |
363 | #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG) \ |
364 | boost::mpl::and_< \ |
365 | TRAIT<BOOST_PROTO_UNCVREF(ARG) > \ |
366 | , boost::mpl::not_<boost::proto::is_extension<ARG> > \ |
367 | > \ |
368 | /**/ |
369 | |
370 | #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT) \ |
371 | boost::mpl::and_< \ |
372 | boost::mpl::or_<TRAIT<BOOST_PROTO_UNCVREF(LEFT) >, TRAIT<BOOST_PROTO_UNCVREF(RIGHT) > > \ |
373 | , boost::mpl::not_< \ |
374 | boost::mpl::or_< \ |
375 | boost::proto::is_extension<LEFT> \ |
376 | , boost::proto::is_extension<RIGHT> \ |
377 | > \ |
378 | > \ |
379 | > \ |
380 | /**/ |
381 | |
382 | #endif |
383 | |
384 | }} |
385 | |
386 | #if defined(_MSC_VER) |
387 | # pragma warning(pop) |
388 | #endif |
389 | |
390 | #endif |
391 | |