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     template<typename Arg>                                                                          \
108     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
109     typename boost::proto::detail::enable_unary<                                                    \
110         DOMAIN                                                                                      \
111       , DOMAIN::proto_grammar                                                                       \
112       , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg)                                                        \
113       , TAG                                                                                         \
114       , Arg &                                                                                       \
115     >::type const                                                                                   \
116     operator OP(Arg &arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST)                                  \
117     {                                                                                               \
118         return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg &>()(arg);                         \
119     }                                                                                               \
120                                                                                                     \
121     template<typename Arg>                                                                          \
122     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
123     typename boost::proto::detail::enable_unary<                                                    \
124         DOMAIN                                                                                      \
125       , DOMAIN::proto_grammar                                                                       \
126       , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg)                                                        \
127       , TAG                                                                                         \
128       , Arg const &                                                                                 \
129     >::type const                                                                                   \
130     operator OP(Arg const &arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST)                            \
131     {                                                                                               \
132         return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg const &>()(arg);                   \
133     }                                                                                               \
134     /**/
135 
136 #define BOOST_PROTO_DEFINE_BINARY_OPERATOR(OP, TAG, TRAIT, DOMAIN)                                  \
137     template<typename Left, typename Right>                                                         \
138     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
139     typename boost::proto::detail::enable_binary<                                                   \
140         DOMAIN                                                                                      \
141       , DOMAIN::proto_grammar                                                                       \
142       , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right)                                               \
143       , TAG                                                                                         \
144       , Left &                                                                                      \
145       , Right &                                                                                     \
146     >::type const                                                                                   \
147     operator OP(Left &left, Right &right)                                                           \
148     {                                                                                               \
149         return boost::proto::detail::make_expr_<TAG, DOMAIN, Left &, Right &>()(left, right);       \
150     }                                                                                               \
151                                                                                                     \
152     template<typename Left, typename Right>                                                         \
153     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
154     typename boost::proto::detail::enable_binary<                                                   \
155         DOMAIN                                                                                      \
156       , DOMAIN::proto_grammar                                                                       \
157       , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right)                                               \
158       , TAG                                                                                         \
159       , Left &                                                                                      \
160       , Right const &                                                                               \
161     >::type const                                                                                   \
162     operator OP(Left &left, Right const &right)                                                     \
163     {                                                                                               \
164         return boost::proto::detail::make_expr_<TAG, DOMAIN, Left &, Right const &>()(left, right); \
165     }                                                                                               \
166                                                                                                     \
167     template<typename Left, typename Right>                                                         \
168     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
169     typename boost::proto::detail::enable_binary<                                                   \
170         DOMAIN                                                                                      \
171       , DOMAIN::proto_grammar                                                                       \
172       , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right)                                               \
173       , TAG                                                                                         \
174       , Left const &                                                                                \
175       , Right &                                                                                     \
176     >::type const                                                                                   \
177     operator OP(Left const &left, Right &right)                                                     \
178     {                                                                                               \
179         return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right &>()(left, right); \
180     }                                                                                               \
181                                                                                                     \
182     template<typename Left, typename Right>                                                         \
183     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
184     typename boost::proto::detail::enable_binary<                                                   \
185         DOMAIN                                                                                      \
186       , DOMAIN::proto_grammar                                                                       \
187       , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right)                                               \
188       , TAG                                                                                         \
189       , Left const &                                                                                \
190       , Right const &                                                                               \
191     >::type const                                                                                   \
192     operator OP(Left const &left, Right const &right)                                               \
193     {                                                                                               \
194         return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right const &>()(left, right);\
195     }                                                                                               \
196     /**/
197 
198 #else
199 
200 #define BOOST_PROTO_DEFINE_UNARY_OPERATOR(OP, TAG, TRAIT, DOMAIN, POST)                             \
201     template<typename Arg>                                                                          \
202     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
203     typename boost::proto::detail::enable_unary<                                                    \
204         DOMAIN                                                                                      \
205       , DOMAIN::proto_grammar                                                                       \
206       , BOOST_PROTO_APPLY_UNARY_(TRAIT, Arg)                                                        \
207       , TAG                                                                                         \
208       , Arg const &                                                                                 \
209     >::type const                                                                                   \
210     operator OP(Arg &&arg BOOST_PROTO_UNARY_OP_IS_POSTFIX_ ## POST)                                 \
211     {                                                                                               \
212         return boost::proto::detail::make_expr_<TAG, DOMAIN, Arg const &>()(arg);                   \
213     }                                                                                               \
214     /**/
215 
216 #define BOOST_PROTO_DEFINE_BINARY_OPERATOR(OP, TAG, TRAIT, DOMAIN)                                  \
217     template<typename Left, typename Right>                                                         \
218     BOOST_PROTO_DISABLE_MSVC_C4714 BOOST_FORCEINLINE                                                \
219     typename boost::proto::detail::enable_binary<                                                   \
220         DOMAIN                                                                                      \
221       , DOMAIN::proto_grammar                                                                       \
222       , BOOST_PROTO_APPLY_BINARY_(TRAIT, Left, Right)                                               \
223       , TAG                                                                                         \
224       , Left const &                                                                                \
225       , Right const &                                                                               \
226     >::type const                                                                                   \
227     operator OP(Left &&left, Right &&right)                                                         \
228     {                                                                                               \
229         return boost::proto::detail::make_expr_<TAG, DOMAIN, Left const &, Right const &>()(left, right);\
230     }                                                                                               \
231     /**/
232 
233 #endif
234 
235 #define BOOST_PROTO_DEFINE_OPERATORS(TRAIT, DOMAIN)                                                 \
236     BOOST_PROTO_DEFINE_UNARY_OPERATOR(+, boost::proto::tag::unary_plus, TRAIT, DOMAIN, 0)           \
237     BOOST_PROTO_DEFINE_UNARY_OPERATOR(-, boost::proto::tag::negate, TRAIT, DOMAIN, 0)               \
238     BOOST_PROTO_DEFINE_UNARY_OPERATOR(*, boost::proto::tag::dereference, TRAIT, DOMAIN, 0)          \
239     BOOST_PROTO_DEFINE_UNARY_OPERATOR(~, boost::proto::tag::complement, TRAIT, DOMAIN, 0)           \
240     BOOST_PROTO_DEFINE_UNARY_OPERATOR(&, boost::proto::tag::address_of, TRAIT, DOMAIN, 0)           \
241     BOOST_PROTO_DEFINE_UNARY_OPERATOR(!, boost::proto::tag::logical_not, TRAIT, DOMAIN, 0)          \
242     BOOST_PROTO_DEFINE_UNARY_OPERATOR(++, boost::proto::tag::pre_inc, TRAIT, DOMAIN, 0)             \
243     BOOST_PROTO_DEFINE_UNARY_OPERATOR(--, boost::proto::tag::pre_dec, TRAIT, DOMAIN, 0)             \
244     BOOST_PROTO_DEFINE_UNARY_OPERATOR(++, boost::proto::tag::post_inc, TRAIT, DOMAIN, 1)            \
245     BOOST_PROTO_DEFINE_UNARY_OPERATOR(--, boost::proto::tag::post_dec, TRAIT, DOMAIN, 1)            \
246     BOOST_PROTO_DEFINE_BINARY_OPERATOR(<<, boost::proto::tag::shift_left, TRAIT, DOMAIN)            \
247     BOOST_PROTO_DEFINE_BINARY_OPERATOR(>>, boost::proto::tag::shift_right, TRAIT, DOMAIN)           \
248     BOOST_PROTO_DEFINE_BINARY_OPERATOR(*, boost::proto::tag::multiplies, TRAIT, DOMAIN)             \
249     BOOST_PROTO_DEFINE_BINARY_OPERATOR(/, boost::proto::tag::divides, TRAIT, DOMAIN)                \
250     BOOST_PROTO_DEFINE_BINARY_OPERATOR(%, boost::proto::tag::modulus, TRAIT, DOMAIN)                \
251     BOOST_PROTO_DEFINE_BINARY_OPERATOR(+, boost::proto::tag::plus, TRAIT, DOMAIN)                   \
252     BOOST_PROTO_DEFINE_BINARY_OPERATOR(-, boost::proto::tag::minus, TRAIT, DOMAIN)                  \
253     BOOST_PROTO_DEFINE_BINARY_OPERATOR(<, boost::proto::tag::less, TRAIT, DOMAIN)                   \
254     BOOST_PROTO_DEFINE_BINARY_OPERATOR(>, boost::proto::tag::greater, TRAIT, DOMAIN)                \
255     BOOST_PROTO_DEFINE_BINARY_OPERATOR(<=, boost::proto::tag::less_equal, TRAIT, DOMAIN)            \
256     BOOST_PROTO_DEFINE_BINARY_OPERATOR(>=, boost::proto::tag::greater_equal, TRAIT, DOMAIN)         \
257     BOOST_PROTO_DEFINE_BINARY_OPERATOR(==, boost::proto::tag::equal_to, TRAIT, DOMAIN)              \
258     BOOST_PROTO_DEFINE_BINARY_OPERATOR(!=, boost::proto::tag::not_equal_to, TRAIT, DOMAIN)          \
259     BOOST_PROTO_DEFINE_BINARY_OPERATOR(||, boost::proto::tag::logical_or, TRAIT, DOMAIN)            \
260     BOOST_PROTO_DEFINE_BINARY_OPERATOR(&&, boost::proto::tag::logical_and, TRAIT, DOMAIN)           \
261     BOOST_PROTO_DEFINE_BINARY_OPERATOR(&, boost::proto::tag::bitwise_and, TRAIT, DOMAIN)            \
262     BOOST_PROTO_DEFINE_BINARY_OPERATOR(|, boost::proto::tag::bitwise_or, TRAIT, DOMAIN)             \
263     BOOST_PROTO_DEFINE_BINARY_OPERATOR(^, boost::proto::tag::bitwise_xor, TRAIT, DOMAIN)            \
264     BOOST_PROTO_DEFINE_BINARY_OPERATOR(BOOST_PP_COMMA(), boost::proto::tag::comma, TRAIT, DOMAIN)   \
265     BOOST_PROTO_DEFINE_BINARY_OPERATOR(->*, boost::proto::tag::mem_ptr, TRAIT, DOMAIN)              \
266     BOOST_PROTO_DEFINE_BINARY_OPERATOR(<<=, boost::proto::tag::shift_left_assign, TRAIT, DOMAIN)    \
267     BOOST_PROTO_DEFINE_BINARY_OPERATOR(>>=, boost::proto::tag::shift_right_assign, TRAIT, DOMAIN)   \
268     BOOST_PROTO_DEFINE_BINARY_OPERATOR(*=, boost::proto::tag::multiplies_assign, TRAIT, DOMAIN)     \
269     BOOST_PROTO_DEFINE_BINARY_OPERATOR(/=, boost::proto::tag::divides_assign, TRAIT, DOMAIN)        \
270     BOOST_PROTO_DEFINE_BINARY_OPERATOR(%=, boost::proto::tag::modulus_assign, TRAIT, DOMAIN)        \
271     BOOST_PROTO_DEFINE_BINARY_OPERATOR(+=, boost::proto::tag::plus_assign, TRAIT, DOMAIN)           \
272     BOOST_PROTO_DEFINE_BINARY_OPERATOR(-=, boost::proto::tag::minus_assign, TRAIT, DOMAIN)          \
273     BOOST_PROTO_DEFINE_BINARY_OPERATOR(&=, boost::proto::tag::bitwise_and_assign, TRAIT, DOMAIN)    \
274     BOOST_PROTO_DEFINE_BINARY_OPERATOR(|=, boost::proto::tag::bitwise_or_assign, TRAIT, DOMAIN)     \
275     BOOST_PROTO_DEFINE_BINARY_OPERATOR(^=, boost::proto::tag::bitwise_xor_assign, TRAIT, DOMAIN)    \
276     /**/
277 
278     // Extensions are a superset of Proto expressions
279     template<typename T>
280     struct is_extension
281       : is_expr<T>
282     {};
283 
284     template<typename T>
285     struct is_extension<T &>
286       : is_expr<T>
287     {};
288 
289     #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG) TRAIT<ARG>
290     #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT) boost::mpl::or_<TRAIT<LEFT>, TRAIT<RIGHT> >
291 
292     namespace exprns_
293     {
294         // This defines all of Proto's built-in free operator overloads
BOOST_PROTO_DEFINE_OPERATORS(is_extension,deduce_domain)295         BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain)
296 
297         // if_else, for the non-overloadable ternary conditional operator ?:
298         template<typename A0, typename A1, typename A2>
299         BOOST_FORCEINLINE
300         typename result_of::make_expr<
301             tag::if_else_
302           , deduce_domain
303           , A0 const &
304           , A1 const &
305           , A2 const &
306         >::type const
307         if_else(A0 const &a0, A1 const &a1, A2 const &a2)
308         {
309             return proto::detail::make_expr_<
310                 tag::if_else_
311               , deduce_domain
312               , A0 const &
313               , A1 const &
314               , A2 const &
315             >()(a0, a1, a2);
316         }
317     }
318 
319     using exprns_::if_else;
320 
321     #undef BOOST_PROTO_APPLY_UNARY_
322     #undef BOOST_PROTO_APPLY_BINARY_
323 
324     // Redefine BOOST_PROTO_APPLY_UNARY_ and BOOST_PROTO_APPLY_BINARY_ so that end users
325     // can use BOOST_PROTO_DEFINE_OPERATORS to define Proto operator overloads that work
326     // with their own terminal types.
327 
328 #ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
329 
330     #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG)                                                    \
331         boost::mpl::and_<                                                                           \
332             TRAIT<ARG>                                                                              \
333           , boost::mpl::not_<boost::proto::is_extension<ARG> >                                      \
334         >                                                                                           \
335         /**/
336 
337     #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT)                                           \
338         boost::mpl::and_<                                                                           \
339             boost::mpl::or_<TRAIT<LEFT>, TRAIT<RIGHT> >                                             \
340           , boost::mpl::not_<                                                                       \
341                 boost::mpl::or_<                                                                    \
342                     boost::proto::is_extension<LEFT>                                                \
343                   , boost::proto::is_extension<RIGHT>                                               \
344                 >                                                                                   \
345             >                                                                                       \
346         >                                                                                           \
347         /**/
348 
349 #else
350 
351     #define BOOST_PROTO_APPLY_UNARY_(TRAIT, ARG)                                                    \
352         boost::mpl::and_<                                                                           \
353             TRAIT<BOOST_PROTO_UNCVREF(ARG) >                                                        \
354           , boost::mpl::not_<boost::proto::is_extension<ARG> >                                      \
355         >                                                                                           \
356         /**/
357 
358     #define BOOST_PROTO_APPLY_BINARY_(TRAIT, LEFT, RIGHT)                                           \
359         boost::mpl::and_<                                                                           \
360             boost::mpl::or_<TRAIT<BOOST_PROTO_UNCVREF(LEFT) >, TRAIT<BOOST_PROTO_UNCVREF(RIGHT) > > \
361           , boost::mpl::not_<                                                                       \
362                 boost::mpl::or_<                                                                    \
363                     boost::proto::is_extension<LEFT>                                                \
364                   , boost::proto::is_extension<RIGHT>                                               \
365                 >                                                                                   \
366             >                                                                                       \
367         >                                                                                           \
368         /**/
369 
370 #endif
371 
372 }}
373 
374 #if defined(_MSC_VER)
375 # pragma warning(pop)
376 #endif
377 
378 #endif
379