scope.qbk 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. [/==============================================================================
  2. Copyright (C) 2001-2010 Joel de Guzman
  3. Copyright (C) 2001-2005 Dan Marsden
  4. Copyright (C) 2001-2010 Thomas Heller
  5. Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. ===============================================================================/]
  8. [section Scope]
  9. Up until now, the most basic ingredient is missing: creation of and access to
  10. local variables in the stack. When recursion comes into play, you will soon
  11. realize the need to have true local variables. It may seem that we do not need
  12. this at all since an unnamed lambda function cannot call itself anyway; at least
  13. not directly. With some sort of arrangement, situations will arise where a
  14. lambda function becomes recursive. A typical situation occurs when we store a
  15. lambda function in a [@http://www.boost.org/libs/function Boost.Function],
  16. essentially naming the unnamed lambda.
  17. There will also be situations where a lambda function gets passed as an argument
  18. to another function. This is a more common situation. In this case, the lambda
  19. function assumes a new scope; new arguments and possibly new local variables.
  20. This section deals with local variables and nested lambda scopes.
  21. [section Local Variables]
  22. #include <boost/phoenix/scope/local_variable.hpp>
  23. We use an instance of:
  24. expression::local_variable<Key>::type
  25. to represent a local variable. The local variable acts as an imaginary data-bin
  26. where a local, stack based data will be placed. `Key` is an arbitrary type that
  27. is used to identify the local variable. Example:
  28. struct size_key;
  29. expression::local_variable<size_key>::type size;
  30. [*Predefined Local Variables]
  31. There are a few predefined instances of `expression::local_variable<Key>::type`
  32. named `_a`..`_z` that you can already use. To make use of them, simply use the
  33. `namespace boost::phoenix::local_names`:
  34. using namespace boost::phoenix::local_names;
  35. [endsect]
  36. [section let]
  37. #include <boost/phoenix/scope/let.hpp>
  38. You declare local variables using the syntax:
  39. let(local-declarations)
  40. [
  41. let-body
  42. ]
  43. `let` allows 1..N local variable declarations (where N ==
  44. `BOOST_PHOENIX_LOCAL_LIMIT`). Each declaration follows the form:
  45. local-id = lambda-expression
  46. [note You can set `BOOST_PHOENIX_LOCAL_LIMIT`, the predefined maximum local
  47. variable declarations in a let expression. By default, `BOOST_PHOENIX_LOCAL_LIMIT` is
  48. set to `BOOST_PHOENIX_LIMIT`.]
  49. Example:
  50. let(_a = 123, _b = 456)
  51. [
  52. _a + _b
  53. ]
  54. [*Reference Preservation]
  55. The type of the local variable assumes the type of the lambda- expression. Type
  56. deduction is reference preserving. For example:
  57. let(_a = arg1, _b = 456)
  58. `_a` assumes the type of `arg1`: a reference to an argument, while `_b` has type
  59. `int`.
  60. Consider this:
  61. int i = 1;
  62. let(_a = arg1)
  63. [
  64. cout << --_a << ' '
  65. ]
  66. (i);
  67. cout << i << endl;
  68. the output of above is : 0 0
  69. While with this:
  70. int i = 1;
  71. let(_a = val(arg1))
  72. [
  73. cout << --_a << ' '
  74. ]
  75. (i);
  76. cout << i << endl;
  77. the output is : 0 1
  78. Reference preservation is necessary because we need to have L-value access to
  79. outer lambda-scopes (especially the arguments). `arg`s and `ref`s are L-values.
  80. `val`s are R-values.
  81. [*Visibility]
  82. [#phoenix.modules.scope.let.visibility]
  83. The scope and lifetimes of the local variables is limited within the let-body.
  84. `let` blocks can be nested. A local variable may hide an outer local variable.
  85. For example:
  86. let(_x = _1, _y = _2)
  87. [
  88. // _x here is an int: 1
  89. let(_x = _3) // hides the outer _x
  90. [
  91. cout << _x << _y // prints "Hello, World"
  92. ]
  93. ](1," World","Hello,");
  94. The actual values of the parameters _1, _2 and _3 are supplied from the
  95. bracketed list at the end of the `let`.
  96. There is currently a limitation that the inner `let` cannot be supplied with a
  97. constant e.g. `let(_x = 1)`.
  98. The RHS (right hand side lambda-expression) of each local-declaration cannot
  99. refer to any LHS local-id. At this point, the local-ids are not in scope yet;
  100. they will only be in scope in the let-body. The code below is in error:
  101. let(
  102. _a = 1
  103. , _b = _a // Error: _a is not in scope yet
  104. )
  105. [
  106. // _a and _b's scope starts here
  107. /*. body .*/
  108. ]
  109. However, if an outer let scope is available, this will be searched. Since
  110. the scope of the RHS of a local-declaration is the outer scope enclosing
  111. the let, the RHS of a local-declaration can refer to a local variable of
  112. an outer scope:
  113. let(_a = 1)
  114. [
  115. let(
  116. _a = _1
  117. , _b = _a // Ok. _a refers to the outer _a
  118. )
  119. [
  120. /*. body .*/
  121. ]
  122. ](1)
  123. [endsect]
  124. [section lambda]
  125. #include <boost/phoenix/scope/lambda.hpp>
  126. A lot of times, you'd want to write a lazy function that accepts one or more
  127. functions (higher order functions). STL algorithms come to mind, for example.
  128. Consider a lazy version of `stl::for_each`:
  129. struct for_each_impl
  130. {
  131. template <typename C, typename F>
  132. struct result
  133. {
  134. typedef void type;
  135. };
  136. template <typename C, typename F>
  137. void operator()(C& c, F f) const
  138. {
  139. std::for_each(c.begin(), c.end(), f);
  140. }
  141. };
  142. function<for_each_impl> const for_each = for_each_impl();
  143. Notice that the function accepts another function, `f` as an argument. The scope
  144. of this function, `f`, is limited within the `operator()`. When `f` is called
  145. inside `std::for_each`, it exists in a new scope, along with new arguments and,
  146. possibly, local variables. This new scope is not at all related to the outer
  147. scopes beyond the `operator()`.
  148. Simple syntax:
  149. lambda
  150. [
  151. lambda-body
  152. ]
  153. Like `let`, local variables may be declared, allowing 1..N local variable
  154. declarations (where N == `BOOST_PHOENIX_LOCAL_LIMIT`):
  155. lambda(local-declarations)
  156. [
  157. lambda-body
  158. ]
  159. The same restrictions apply with regard to scope and visibility. The RHS
  160. (right hand side lambda-expression) of each local-declaration cannot refer
  161. to any LHS local-id. The local-ids are not in scope yet; they will be in
  162. scope only in the lambda-body:
  163. lambda(
  164. _a = 1
  165. , _b = _a // Error: _a is not in scope yet
  166. )
  167. See [link phoenix.modules.scope.let.visibility `let` Visibility] for more information.
  168. Example: Using our lazy `for_each` let's print all the elements in a container:
  169. for_each(arg1, lambda[cout << arg1])
  170. As far as the arguments are concerned (arg1..argN), the scope in which the
  171. lambda-body exists is totally new. The left `arg1` refers to the argument passed
  172. to `for_each` (a container). The right `arg1` refers to the argument passed by
  173. `std::for_each` when we finally get to call `operator()` in our `for_each_impl`
  174. above (a container element).
  175. Yet, we may wish to get information from outer scopes. While we do not have
  176. access to arguments in outer scopes, what we still have is access to local
  177. variables from outer scopes. We may only be able to pass argument related
  178. information from outer `lambda` scopes through the local variables.
  179. [note This is a crucial difference between `let` and `lambda`: `let`
  180. does not introduce new arguments; `lambda` does.]
  181. Another example: Using our lazy `for_each`, and a lazy `push_back`:
  182. struct push_back_impl
  183. {
  184. template <typename C, typename T>
  185. struct result
  186. {
  187. typedef void type;
  188. };
  189. template <typename C, typename T>
  190. void operator()(C& c, T& x) const
  191. {
  192. c.push_back(x);
  193. }
  194. };
  195. function<push_back_impl> const push_back = push_back_impl();
  196. write a lambda expression that accepts:
  197. # a 2-dimensional container (e.g. `vector<vector<int> >`)
  198. # a container element (e.g. `int`)
  199. and pushes-back the element to each of the `vector<int>`.
  200. Solution:
  201. for_each(arg1,
  202. lambda(_a = arg2)
  203. [
  204. push_back(arg1, _a)
  205. ]
  206. )
  207. Since we do not have access to the arguments of the outer scopes beyond the
  208. lambda-body, we introduce a local variable `_a` that captures the second outer
  209. argument: `arg2`. Hence: _a = arg2. This local variable is visible inside the
  210. lambda scope.
  211. (See [@../../example/lambda.cpp lambda.cpp])
  212. [endsect]
  213. [endsect]