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