pack_expansion.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // pack_expansion.hpp
  3. //
  4. // Copyright 2008 Eric Niebler. Distributed under the Boost
  5. // Software License, Version 1.0. (See accompanying file
  6. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. #include <boost/proto/proto.hpp>
  8. #include <boost/test/unit_test.hpp>
  9. #include <boost/typeof/typeof.hpp>
  10. namespace mpl = boost::mpl;
  11. namespace proto = boost::proto;
  12. using proto::_;
  13. template<typename T> T declval();
  14. struct eval_ : proto::callable
  15. {
  16. template<typename Sig>
  17. struct result;
  18. #define UNARY_OP(TAG, OP) \
  19. template<typename This, typename Arg> \
  20. struct result<This(proto::tag::TAG, Arg)> \
  21. { \
  22. BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>())) \
  23. typedef typename nested::type type; \
  24. }; \
  25. \
  26. template<typename Arg> \
  27. typename result<eval_(proto::tag::TAG, Arg)>::type \
  28. operator()(proto::tag::TAG, Arg arg) const \
  29. { \
  30. return OP arg; \
  31. } \
  32. /**/
  33. #define BINARY_OP(TAG, OP) \
  34. template<typename This, typename Left, typename Right> \
  35. struct result<This(proto::tag::TAG, Left, Right)> \
  36. { \
  37. BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \
  38. typedef typename nested::type type; \
  39. }; \
  40. \
  41. template<typename Left, typename Right> \
  42. typename result<eval_(proto::tag::TAG, Left, Right)>::type \
  43. operator()(proto::tag::TAG, Left left, Right right) const \
  44. { \
  45. return left OP right; \
  46. } \
  47. /**/
  48. UNARY_OP(negate, -)
  49. BINARY_OP(plus, +)
  50. BINARY_OP(minus, -)
  51. BINARY_OP(multiplies, *)
  52. BINARY_OP(divides, /)
  53. /*... others ...*/
  54. };
  55. struct eval1
  56. : proto::or_<
  57. proto::when<proto::terminal<_>, proto::_value>
  58. , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)>
  59. >
  60. {};
  61. struct eval2
  62. : proto::or_<
  63. proto::when<proto::terminal<_>, proto::_value>
  64. , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> >
  65. >
  66. {};
  67. void test_call_pack()
  68. {
  69. proto::terminal<int>::type i = {42};
  70. int res = eval1()(i);
  71. BOOST_CHECK_EQUAL(res, 42);
  72. res = eval1()(i + 2);
  73. BOOST_CHECK_EQUAL(res, 44);
  74. res = eval1()(i * 2);
  75. BOOST_CHECK_EQUAL(res, 84);
  76. res = eval1()(i * 2 + 4);
  77. BOOST_CHECK_EQUAL(res, 88);
  78. res = eval2()(i + 2);
  79. BOOST_CHECK_EQUAL(res, 44);
  80. res = eval2()(i * 2);
  81. BOOST_CHECK_EQUAL(res, 84);
  82. res = eval2()(i * 2 + 4);
  83. BOOST_CHECK_EQUAL(res, 88);
  84. }
  85. struct make_pair
  86. : proto::when<
  87. proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> >
  88. , std::pair<int, int>(proto::_value(proto::pack(_))...)
  89. >
  90. {};
  91. void test_make_pack()
  92. {
  93. proto::terminal<int>::type i = {42};
  94. std::pair<int, int> p = make_pair()(i + 43);
  95. BOOST_CHECK_EQUAL(p.first, 42);
  96. BOOST_CHECK_EQUAL(p.second, 43);
  97. }
  98. using namespace boost::unit_test;
  99. ///////////////////////////////////////////////////////////////////////////////
  100. // init_unit_test_suite
  101. //
  102. test_suite* init_unit_test_suite( int argc, char* argv[] )
  103. {
  104. test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees");
  105. test->add(BOOST_TEST_CASE(&test_call_pack));
  106. test->add(BOOST_TEST_CASE(&test_make_pack));
  107. return test;
  108. }