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
BOOST_PROTO_DEFINE_OPERATORS(is_extension,deduce_domain)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