]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/phoenix/doc/modules/scope.qbk
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / phoenix / doc / modules / scope.qbk
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]