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