operators.hpp 24 KB

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