operators.hpp 25 KB

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