mini_lambda.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //[ Lambda
  2. ///////////////////////////////////////////////////////////////////////////////
  3. // Copyright 2008 Eric Niebler. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // This example builds a simple but functional lambda library using Proto.
  8. #include <iostream>
  9. #include <algorithm>
  10. #include <boost/mpl/int.hpp>
  11. #include <boost/mpl/min_max.hpp>
  12. #include <boost/mpl/eval_if.hpp>
  13. #include <boost/mpl/identity.hpp>
  14. #include <boost/mpl/next_prior.hpp>
  15. #include <boost/fusion/tuple.hpp>
  16. #include <boost/typeof/typeof.hpp>
  17. #include <boost/typeof/std/ostream.hpp>
  18. #include <boost/typeof/std/iostream.hpp>
  19. #include <boost/proto/core.hpp>
  20. #include <boost/proto/context.hpp>
  21. #include <boost/proto/transform.hpp>
  22. namespace mpl = boost::mpl;
  23. namespace proto = boost::proto;
  24. namespace fusion = boost::fusion;
  25. using proto::_;
  26. // Forward declaration of the lambda expression wrapper
  27. template<typename T>
  28. struct lambda;
  29. struct lambda_domain
  30. : proto::domain<proto::pod_generator<lambda> >
  31. {};
  32. template<typename I>
  33. struct placeholder
  34. {
  35. typedef I arity;
  36. };
  37. template<typename T>
  38. struct placeholder_arity
  39. {
  40. typedef typename T::arity type;
  41. };
  42. // The lambda grammar, with the transforms for calculating the max arity
  43. struct lambda_arity
  44. : proto::or_<
  45. proto::when<
  46. proto::terminal< placeholder<_> >
  47. , mpl::next<placeholder_arity<proto::_value> >()
  48. >
  49. , proto::when< proto::terminal<_>
  50. , mpl::int_<0>()
  51. >
  52. , proto::when<
  53. proto::nary_expr<_, proto::vararg<_> >
  54. , proto::fold<_, mpl::int_<0>(), mpl::max<lambda_arity, proto::_state>()>
  55. >
  56. >
  57. {};
  58. // The lambda context is the same as the default context
  59. // with the addition of special handling for lambda placeholders
  60. template<typename Tuple>
  61. struct lambda_context
  62. : proto::callable_context<lambda_context<Tuple> const>
  63. {
  64. lambda_context(Tuple const &args)
  65. : args_(args)
  66. {}
  67. template<typename Sig>
  68. struct result;
  69. template<typename This, typename I>
  70. struct result<This(proto::tag::terminal, placeholder<I> const &)>
  71. : fusion::result_of::at<Tuple, I>
  72. {};
  73. template<typename I>
  74. typename fusion::result_of::at<Tuple, I>::type
  75. operator ()(proto::tag::terminal, placeholder<I> const &) const
  76. {
  77. return fusion::at<I>(this->args_);
  78. }
  79. Tuple args_;
  80. };
  81. // The lambda<> expression wrapper makes expressions polymorphic
  82. // function objects
  83. template<typename T>
  84. struct lambda
  85. {
  86. BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)
  87. BOOST_PROTO_EXTENDS_ASSIGN()
  88. BOOST_PROTO_EXTENDS_SUBSCRIPT()
  89. // Calculate the arity of this lambda expression
  90. static int const arity = boost::result_of<lambda_arity(T)>::type::value;
  91. template<typename Sig>
  92. struct result;
  93. // Define nested result<> specializations to calculate the return
  94. // type of this lambda expression. But be careful not to evaluate
  95. // the return type of the nullary function unless we have a nullary
  96. // lambda!
  97. template<typename This>
  98. struct result<This()>
  99. : mpl::eval_if_c<
  100. 0 == arity
  101. , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >
  102. , mpl::identity<void>
  103. >
  104. {};
  105. template<typename This, typename A0>
  106. struct result<This(A0)>
  107. : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0> > >
  108. {};
  109. template<typename This, typename A0, typename A1>
  110. struct result<This(A0, A1)>
  111. : proto::result_of::eval<T const, lambda_context<fusion::tuple<A0, A1> > >
  112. {};
  113. // Define our operator () that evaluates the lambda expression.
  114. typename result<lambda()>::type
  115. operator ()() const
  116. {
  117. fusion::tuple<> args;
  118. lambda_context<fusion::tuple<> > ctx(args);
  119. return proto::eval(*this, ctx);
  120. }
  121. template<typename A0>
  122. typename result<lambda(A0 const &)>::type
  123. operator ()(A0 const &a0) const
  124. {
  125. fusion::tuple<A0 const &> args(a0);
  126. lambda_context<fusion::tuple<A0 const &> > ctx(args);
  127. return proto::eval(*this, ctx);
  128. }
  129. template<typename A0, typename A1>
  130. typename result<lambda(A0 const &, A1 const &)>::type
  131. operator ()(A0 const &a0, A1 const &a1) const
  132. {
  133. fusion::tuple<A0 const &, A1 const &> args(a0, a1);
  134. lambda_context<fusion::tuple<A0 const &, A1 const &> > ctx(args);
  135. return proto::eval(*this, ctx);
  136. }
  137. };
  138. // Define some lambda placeholders
  139. lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}};
  140. lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}};
  141. template<typename T>
  142. lambda<typename proto::terminal<T>::type> const val(T const &t)
  143. {
  144. lambda<typename proto::terminal<T>::type> that = {{t}};
  145. return that;
  146. }
  147. template<typename T>
  148. lambda<typename proto::terminal<T &>::type> const var(T &t)
  149. {
  150. lambda<typename proto::terminal<T &>::type> that = {{t}};
  151. return that;
  152. }
  153. template<typename T>
  154. struct construct_helper
  155. {
  156. typedef T result_type; // for TR1 result_of
  157. T operator()() const
  158. { return T(); }
  159. // Generate BOOST_PROTO_MAX_ARITY overloads of the
  160. // following function call operator.
  161. #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a)\
  162. template<typename_A(N)> \
  163. T operator()(A_const_ref_a(N)) const \
  164. { return T(a(N)); }
  165. #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a
  166. #include BOOST_PROTO_LOCAL_ITERATE()
  167. };
  168. // Generate BOOST_PROTO_MAX_ARITY-1 overloads of the
  169. // following construct() function template.
  170. #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \
  171. template<typename T, typename_A(N)> \
  172. typename proto::result_of::make_expr< \
  173. proto::tag::function \
  174. , lambda_domain \
  175. , construct_helper<T> \
  176. , A_const_ref(N) \
  177. >::type const \
  178. construct(A_const_ref_a(N)) \
  179. { \
  180. return proto::make_expr< \
  181. proto::tag::function \
  182. , lambda_domain \
  183. >( \
  184. construct_helper<T>() \
  185. , ref_a(N) \
  186. ); \
  187. }
  188. BOOST_PROTO_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0)
  189. #undef M0
  190. struct S
  191. {
  192. S() {}
  193. S(int i, char c)
  194. {
  195. std::cout << "S(" << i << "," << c << ")\n";
  196. }
  197. };
  198. int main()
  199. {
  200. // Create some lambda objects and immediately
  201. // invoke them by applying their operator():
  202. int i = ( (_1 + 2) / 4 )(42);
  203. std::cout << i << std::endl; // prints 11
  204. int j = ( (-(_1 + 2)) / 4 )(42);
  205. std::cout << j << std::endl; // prints -11
  206. double d = ( (4 - _2) * 3 )(42, 3.14);
  207. std::cout << d << std::endl; // prints 2.58
  208. // check non-const ref terminals
  209. (std::cout << _1 << " -- " << _2 << '\n')(42, "Life, the Universe and Everything!");
  210. // prints "42 -- Life, the Universe and Everything!"
  211. // "Nullary" lambdas work too
  212. int k = (val(1) + val(2))();
  213. std::cout << k << std::endl; // prints 3
  214. // check array indexing for kicks
  215. int integers[5] = {0};
  216. (var(integers)[2] = 2)();
  217. (var(integers)[_1] = _1)(3);
  218. std::cout << integers[2] << std::endl; // prints 2
  219. std::cout << integers[3] << std::endl; // prints 3
  220. // Now use a lambda with an STL algorithm!
  221. int rgi[4] = {1,2,3,4};
  222. char rgc[4] = {'a','b','c','d'};
  223. S rgs[4];
  224. std::transform(rgi, rgi+4, rgc, rgs, construct<S>(_1, _2));
  225. return 0;
  226. }
  227. //]